Compare commits

..

4 Commits

Author SHA1 Message Date
dcf7ef34ab Updates for release
Some checks failed
Release / Publish to crates.io (push) Failing after 2m10s
CI / CI (push) Successful in 8m30s
Release / Publish to Docker Hub (push) Successful in 4m37s
2023-09-22 22:13:23 -07:00
4c84269c03 Fix log printing on main errors 2023-09-22 22:12:46 -07:00
dc41aeac14 Add support for reading mail-archive.com RSS feeds 2023-09-22 22:12:44 -07:00
092b29637f Rearrange the code a bit
I'm prepping to make bebot do more things than just be a gitlab webhook
handler, so I've moved the gitlab stuff into its own module (and some of
the matrix helper functions too, for good measure).

The config file also now puts all the gitlab-specific configuration
under a 'gitlab' key.
2023-09-20 21:57:26 -07:00
10 changed files with 1641 additions and 353 deletions

215
Cargo.lock generated
View File

@ -37,6 +37,21 @@ dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.75"
@ -55,6 +70,19 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f093eed78becd229346bf859eec0aa4dd7ddde0757287b2b4107a1f09c80002"
[[package]]
name = "async-compression"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb42b2197bf15ccb092b62c74515dbd8b86d0effd934795f6687c93b6e679a2c"
dependencies = [
"flate2",
"futures-core",
"memchr",
"pin-project-lite",
"tokio",
]
[[package]]
name = "async-lock"
version = "2.8.0"
@ -152,15 +180,20 @@ checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "bebot"
version = "0.1.3-alpha.1"
version = "0.2.0"
dependencies = [
"anyhow",
"chrono",
"constant_time_eq",
"dateparser",
"env_logger",
"futures",
"http",
"log",
"matrix-sdk",
"quick-xml",
"regex",
"reqwest",
"serde",
"serde_json",
"serde_regex",
@ -223,12 +256,43 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "constant_time_eq"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "cpufeatures"
version = "0.2.9"
@ -238,6 +302,15 @@ dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -296,6 +369,18 @@ dependencies = [
"parking_lot_core 0.9.8",
]
[[package]]
name = "dateparser"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18e537db44ee4822af930a9a2c9eedfcde9d47e01c6731fbf34ea01b5a7ccf7d"
dependencies = [
"anyhow",
"chrono",
"lazy_static",
"regex",
]
[[package]]
name = "derive_builder"
version = "0.11.2"
@ -398,6 +483,16 @@ version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "flate2"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -697,6 +792,29 @@ dependencies = [
"tokio-rustls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -793,6 +911,12 @@ dependencies = [
"serde",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.148"
@ -971,6 +1095,15 @@ dependencies = [
"version_check",
]
[[package]]
name = "num-traits"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
@ -996,6 +1129,12 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -1108,6 +1247,16 @@ dependencies = [
"unicase",
]
[[package]]
name = "quick-xml"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "quote"
version = "1.0.33"
@ -1200,6 +1349,7 @@ version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [
"async-compression",
"base64 0.21.4",
"bytes",
"encoding_rs",
@ -1218,12 +1368,14 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls-native-certs",
"rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-rustls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
@ -1377,6 +1529,18 @@ dependencies = [
"sct",
]
[[package]]
name = "rustls-native-certs"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
dependencies = [
"openssl-probe",
"rustls-pemfile",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.3"
@ -1388,9 +1552,9 @@ dependencies = [
[[package]]
name = "rustls-webpki"
version = "0.101.5"
version = "0.101.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed"
checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe"
dependencies = [
"ring",
"untrusted",
@ -1402,6 +1566,15 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@ -1424,6 +1597,29 @@ dependencies = [
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "serde"
version = "1.0.188"
@ -1492,9 +1688,9 @@ dependencies = [
[[package]]
name = "sha1"
version = "0.10.5"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
@ -2045,6 +2241,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.48.0"

View File

@ -1,6 +1,6 @@
[package]
name = "bebot"
version = "0.1.3-alpha.1"
version = "0.2.0"
description = "Gitlab webhook bot that publishes events to Matrix"
license = "GPL-3.0"
authors = [
@ -24,15 +24,20 @@ exclude = [
[dependencies]
anyhow = "1"
chrono = { version = "0.4", features = ["serde"] }
constant_time_eq = "0.3"
dateparser = "0.2"
env_logger = "0.10"
futures = "0.3"
http = "0.2"
log = { version = "0.4", features = ["std"] }
matrix-sdk = { version = "0.6", features = ["anyhow", "markdown", "rustls-tls"], default-features = false }
quick-xml = { version = "0.30", features = ["serialize"] }
regex = "1"
reqwest = { version = "0.11", default-features = false, features = ["tokio-rustls", "rustls-tls-native-roots", "gzip"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_regex = "1"
serde_yaml = "0.9"
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "macros"] }
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "macros", "time"] }
warp = "0.3"

View File

@ -2,57 +2,59 @@
bind_address: 127.0.0.1
# Port the webhook listener should bind to (default is 3000).
bind_port: 3000
# Optional prefix to serve the webhook path under (default is empty string).
url_prefix: "/bebot"
# Matrix user to sign in as.
user_id: "@mybebot:example.com"
# Password for Matrix user.
password: "secret-matrix-account-password"
# Default Matrix room to publish events to.
default_room: "#my-project-commits:example.com"
# Default set of events to publish. If left out, all events will be published.
default_publish_events:
- name: push
# Regexes of branch names. Leave out entirely for "all branches".
branches:
- '^main$'
- '^xfce-.+'
- name: tag_push
- name: issues
# See the Gitlab docs for a full list of actions. If left out, all actions
# will be published.
actions:
- open
- close
- name: merge_request
# See the Gitlab docs for a full list of actions. If left out, all actions
# will be published.
actions:
- open
- merge
- name: pipeline
# See the Gitlab docs for a full list of statuses. If left out, all
# actions will be published.
statuses:
- failed
# Key-value configuration for repositories.
repo_configs:
# Keys are the instance name / namespace / repository name
"gitlab.example.com/myorg/my-cool-app":
# Each repository should use a unique, randomly-generated token. Enter
# this token in the webhook configuration's "Secret token" on Gitlab.
token: "abcdefg12345"
# You can override the default_room above. Leave out to use the default.
room: "#my-cool-app-events:example.com"
# You can override default_events above. Leave out this section to
# use the defaults.
publish_events:
- name: push
branches:
- main
- name: pipeline
statuses:
- failed
"gitlab.example.com/myuser/some-other-less-cool-app":
token: "kljaslkdjaklsdjalksd"
# This repo uses the default events and room.
# All Gitlab-specific settings are under here.
gitlab:
# Optional prefix to serve the webhook path under (default is empty string).
url_prefix: "/bebot"
# Default Matrix room to publish Gitlab events to.
default_room: "#my-project-commits:example.com"
# Default set of events to publish. If left out, all events will be published.
default_publish_events:
- name: push
# Regexes of branch names. Leave out entirely for "all branches".
branches:
- '^main$'
- '^xfce-.+'
- name: tag_push
- name: issues
# See the Gitlab docs for a full list of actions. If left out, all actions
# will be published.
actions:
- open
- close
- name: merge_request
# See the Gitlab docs for a full list of actions. If left out, all actions
# will be published.
actions:
- open
- merge
- name: pipeline
# See the Gitlab docs for a full list of statuses. If left out, all
# actions will be published.
statuses:
- failed
# Key-value configuration for repositories.
repo_configs:
# Keys are the instance name / namespace / repository name
"gitlab.example.com/myorg/my-cool-app":
# Each repository should use a unique, randomly-generated token. Enter
# this token in the webhook configuration's "Secret token" on Gitlab.
token: "abcdefg12345"
# You can override the default_room above. Leave out to use the default.
room: "#my-cool-app-events:example.com"
# You can override default_events above. Leave out this section to
# use the defaults.
publish_events:
- name: push
branches:
- main
- name: pipeline
statuses:
- failed
"gitlab.example.com/myuser/some-other-less-cool-app":
token: "kljaslkdjaklsdjalksd"
# This repo uses the default events and room.

View File

@ -14,14 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::{collections::HashMap, fmt, fs::File, io::BufReader};
use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf};
use anyhow::Context;
use matrix_sdk::ruma::{OwnedRoomOrAliasId, OwnedUserId, RoomOrAliasId, UserId};
use matrix_sdk::ruma::{OwnedRoomOrAliasId, OwnedUserId};
use regex::Regex;
use serde::de;
use crate::event::{IssueAction, MergeRequestAction, PipelineStatus};
use crate::gitlab_event::{IssueAction, MergeRequestAction, PipelineStatus};
#[derive(Deserialize)]
#[serde(tag = "name", rename_all = "snake_case")]
@ -47,111 +46,47 @@ pub enum PublishEvent {
pub struct RepoConfig {
pub token: String,
#[serde(default)]
#[serde(deserialize_with = "deser_optional_room_or_alias_id")]
#[serde(deserialize_with = "crate::matrix::deser_optional_room_or_alias_id")]
pub room: Option<OwnedRoomOrAliasId>,
pub publish_events: Option<Vec<PublishEvent>>,
}
#[derive(Deserialize)]
pub struct Config {
pub bind_address: Option<String>,
pub bind_port: Option<u16>,
pub struct GitlabWebhookConfig {
pub url_prefix: Option<String>,
#[serde(deserialize_with = "deser_user_id")]
pub user_id: OwnedUserId,
pub password: String,
#[serde(default)]
#[serde(deserialize_with = "deser_optional_room_or_alias_id")]
#[serde(deserialize_with = "crate::matrix::deser_optional_room_or_alias_id")]
pub default_room: Option<OwnedRoomOrAliasId>,
pub default_publish_events: Option<Vec<PublishEvent>>,
pub repo_configs: HashMap<String, RepoConfig>, // key is repo url without scheme; e.g.
// gitlab.xfce.org/xfce/xfdesktop
}
fn deser_user_id<'de, D>(deserializer: D) -> Result<OwnedUserId, D::Error>
where
D: de::Deserializer<'de>,
{
struct UserIdVisitor;
impl<'de> de::Visitor<'de> for UserIdVisitor {
type Value = OwnedUserId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a matrix user ID")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
UserId::parse(v).map_err(E::custom)
}
}
deserializer.deserialize_any(UserIdVisitor)
#[derive(Clone, Deserialize)]
pub struct MailListConfig {
pub name: String,
#[serde(default)]
pub rooms: Vec<OwnedRoomOrAliasId>,
}
fn deser_room_or_alias_id<'de, D>(deserializer: D) -> Result<OwnedRoomOrAliasId, D::Error>
where
D: de::Deserializer<'de>,
{
struct RoomOrAliasIdVisitor;
impl<'de> de::Visitor<'de> for RoomOrAliasIdVisitor {
type Value = OwnedRoomOrAliasId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a matrix room ID")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
RoomOrAliasId::parse(v).map_err(E::custom)
}
}
deserializer.deserialize_any(RoomOrAliasIdVisitor)
#[derive(Deserialize)]
pub struct MailArchiveConfig {
#[serde(default)]
pub default_rooms: Vec<OwnedRoomOrAliasId>,
pub update_interval: u64, // seconds
pub state_dir: PathBuf,
pub lists: Vec<MailListConfig>,
}
fn deser_optional_room_or_alias_id<'de, D>(deserializer: D) -> Result<Option<OwnedRoomOrAliasId>, D::Error>
where
D: de::Deserializer<'de>,
{
struct OptionalRoomOrAliasIdVisitor;
impl<'de> de::Visitor<'de> for OptionalRoomOrAliasIdVisitor {
type Value = Option<OwnedRoomOrAliasId>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("null or matrix room ID")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Some(deser_room_or_alias_id(deserializer)?))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
RoomOrAliasId::parse(v).map(Some).map_err(E::custom)
}
}
deserializer.deserialize_any(OptionalRoomOrAliasIdVisitor)
#[derive(Deserialize)]
pub struct Config {
pub bind_address: Option<String>,
pub bind_port: Option<u16>,
#[serde(deserialize_with = "crate::matrix::deser_user_id")]
pub user_id: OwnedUserId,
pub password: String,
pub gitlab_webhook: Option<GitlabWebhookConfig>,
pub mail_archive: Option<MailArchiveConfig>,
}
fn load_blocking(path: &String) -> anyhow::Result<Config> {

145
src/gitlab_webhook.rs Normal file
View File

@ -0,0 +1,145 @@
// bebot
// Copyright (C) 2023 Brian Tarricone <brian@tarricone.org>
//
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use constant_time_eq::constant_time_eq;
use http::StatusCode;
use matrix_sdk::{
ruma::{events::room::message::RoomMessageEventContent, OwnedRoomOrAliasId},
Client,
};
use tokio::sync::mpsc;
use warp::{filters::BoxedFilter, reply::Reply, Filter};
use crate::{
config::GitlabWebhookConfig,
gitlab_event::{parse_ref, GitlabEvent, GitlabEventExt},
matrix,
};
pub fn build_gitlab_messages(event: &GitlabEvent) -> Vec<String> {
let project = event.project();
let refname = event.r#ref().map(parse_ref);
event
.titles()
.iter()
.map(|title| {
format!(
"\\[{}\\] {}*{}* {}",
project.path_with_namespace,
refname
.as_ref()
.map(|rn| format!("`{}` ", rn))
.unwrap_or_else(|| "".to_string()),
event.user(),
title,
)
})
.collect()
}
pub async fn handle_gitlab_event(
event: GitlabEvent,
room_id: &OwnedRoomOrAliasId,
matrix_client: &Client,
) -> anyhow::Result<()> {
let room = matrix::ensure_room_joined(matrix_client, room_id).await?;
for msg in build_gitlab_messages(&event) {
debug!("Sending message to {}: {}", room_id, msg);
let msg_content = RoomMessageEventContent::text_markdown(&msg);
room.send(msg_content, None).await?;
}
Ok(())
}
pub fn build_route(config: GitlabWebhookConfig, matrix_client: Client) -> anyhow::Result<BoxedFilter<(impl Reply,)>> {
let (event_tx, mut event_rx) = mpsc::channel::<(GitlabEvent, OwnedRoomOrAliasId)>(100);
tokio::spawn(async move {
while let Some((event, room)) = event_rx.recv().await {
if let Err(err) = handle_gitlab_event(event, &room, &matrix_client).await {
warn!("Failed to handle payload: {}", err);
}
}
});
let gitlab_root_path = if let Some(url_prefix) = config.url_prefix.as_ref() {
url_prefix.split('/').fold(warp::any().boxed(), |last, segment| {
if segment.is_empty() {
last
} else {
last.and(warp::path(segment.to_string())).boxed()
}
})
} else {
warp::any().boxed()
};
let config = Arc::new(config);
let gitlab = gitlab_root_path
.and(warp::path!("hooks" / "gitlab"))
.and(warp::post())
.and(warp::header::<String>("x-gitlab-token"))
.and(warp::body::json())
.then(move |token: String, event: GitlabEvent| {
let event_tx = event_tx.clone();
let config = Arc::clone(&config);
async move {
match event {
GitlabEvent::Other => {
warp::reply::with_status("Unsupported Gitlab event type", StatusCode::BAD_REQUEST)
}
_ => {
let project = event.project();
let config_key = project.web_url.replace("http://", "").replace("https://", "");
if let Some(repo_config) = config.repo_configs.get(&config_key) {
if !constant_time_eq(token.as_bytes(), repo_config.token.as_bytes()) {
warn!("Invalid token for repo '{}'", config_key);
warp::reply::with_status("Invalid token", StatusCode::FORBIDDEN)
} else {
debug!("payload: {:?}", event);
if let Some(room) = &repo_config.room.as_ref().or(config.default_room.as_ref()) {
let publish_events = repo_config
.publish_events
.as_ref()
.or(config.default_publish_events.as_ref());
if publish_events.map(|ecs| event.should_publish(ecs)).unwrap_or(true) {
if let Err(err) = event_tx.send((event, (*room).clone())).await {
warn!("Failed to enqueue payload: {}", err);
}
}
warp::reply::with_status("OK", StatusCode::OK)
} else {
info!("Channel not configured for repo '{}'", config_key);
warp::reply::with_status(
"Matrix room not configured for repo",
StatusCode::NOT_FOUND,
)
}
}
} else {
info!("Repo '{}' unconfigured", config_key);
warp::reply::with_status("Repo not configured", StatusCode::NOT_FOUND)
}
}
}
}
})
.boxed();
Ok(gitlab)
}

262
src/mail_archive.rs Normal file
View File

@ -0,0 +1,262 @@
// bebot
// Copyright (C) 2023 Brian Tarricone <brian@tarricone.org>
//
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::{
fmt,
io::{BufReader, BufWriter, ErrorKind},
path::PathBuf,
time::{Duration, SystemTime},
};
use anyhow::Context;
use chrono::{DateTime, Utc};
use futures::{future::join_all, FutureExt};
use matrix_sdk::{
ruma::{events::room::message::RoomMessageEventContent, OwnedRoomOrAliasId},
Client,
};
use reqwest::redirect;
use serde::de;
use tokio::{fs::File, task::JoinHandle, time::sleep};
use crate::{
config::{MailArchiveConfig, MailListConfig},
matrix,
};
#[derive(Clone, Copy, Serialize, Deserialize)]
struct ListState {
last_pub_date: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
struct RssPubDate {
#[serde(rename = "$text", deserialize_with = "deser_rfc2616")]
value: DateTime<Utc>,
}
#[derive(Debug, Deserialize)]
struct RssItem {
title: String,
link: String,
#[serde(rename = "pubDate")]
pub_date: RssPubDate,
}
#[derive(Debug, Deserialize)]
struct RssChannel {
#[serde(rename = "item")]
items: Vec<RssItem>,
}
#[derive(Debug, Deserialize)]
struct MailRss {
channel: RssChannel,
}
async fn load_list_state(state_file: &PathBuf) -> anyhow::Result<ListState> {
match File::open(state_file).await {
Err(err) if err.kind() == ErrorKind::NotFound => {
// If we have no state, we probably don't want to blast out events
// for every single item in the RSS feed, so pretend the last time
// we published was right now.
let list_state = ListState {
last_pub_date: SystemTime::now().into(),
};
save_list_state(list_state, state_file).await?;
Ok(list_state)
}
Err(err) => Err(err)?,
Ok(f) => {
let r = BufReader::new(f.into_std().await);
Ok(tokio::task::spawn_blocking(move || serde_yaml::from_reader(r)).await??)
}
}
}
async fn save_list_state(list_state: ListState, state_file: &PathBuf) -> anyhow::Result<()> {
let f = File::options()
.write(true)
.truncate(true)
.create(true)
.open(state_file)
.await?;
let w = BufWriter::new(f.into_std().await);
tokio::task::spawn_blocking(move || serde_yaml::to_writer(w, &list_state)).await??;
Ok(())
}
async fn handle_list(
list: &MailListConfig,
state_file: &PathBuf,
http_client: &reqwest::Client,
url: &String,
matrix_client: &Client,
room_ids: &[OwnedRoomOrAliasId],
) -> anyhow::Result<()> {
let list_state = load_list_state(state_file).await?;
let rooms_f = room_ids.iter().map(|room_id| {
matrix::ensure_room_joined(matrix_client, room_id)
.map(move |res| res.with_context(|| format!("Failed to join Matrix room '{}'", room_id)))
});
let rooms = join_all(rooms_f)
.await
.into_iter()
.flat_map(|room_res| match room_res {
Err(err) => {
warn!("{:#}", err);
vec![]
}
Ok(room) => vec![room],
})
.collect::<Vec<_>>();
if rooms.is_empty() {
return Err(anyhow!("Failed to join all rooms for list '{}'; skipping", list.name));
}
let response = http_client
.get(url)
.send()
.await
.with_context(|| format!("Failed to fetch mail RSS feed from '{}'", url))
.and_then(|response| {
if !response.status().is_success() {
Err(anyhow!(
"Failed to fetch mail RSS feed from '{}': server returned status {}",
url,
response.status().as_u16()
))
} else {
Ok(response)
}
})?;
let body = response
.text()
.await
.with_context(|| format!("Failed to decode RSS response body for '{}'", url))?;
let mail_rss = tokio::task::spawn_blocking(move || quick_xml::de::from_str::<MailRss>(&body))
.await?
.with_context(|| format!("Failed to parse RSS feed for '{}'", url))?;
let items = mail_rss
.channel
.items
.into_iter()
.rev()
.skip_while(|item| item.pub_date.value <= list_state.last_pub_date)
.collect::<Vec<_>>();
for room in rooms {
for item in &items {
let msg =
RoomMessageEventContent::text_markdown(format!("\\[{}\\] [{}]({}]", list.name, item.title, item.link));
room.send(msg, None)
.await
.with_context(|| format!("Failed to send message to room '{}'", room.room_id()))?;
save_list_state(
ListState {
last_pub_date: item.pub_date.value,
},
state_file,
)
.await?;
}
}
Ok(())
}
pub fn start_polling(config: MailArchiveConfig, matrix_client: Client) -> anyhow::Result<Vec<JoinHandle<()>>> {
let http_client = reqwest::Client::builder()
.user_agent(format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")))
.gzip(true)
.redirect(redirect::Policy::default())
.timeout(Duration::from_secs(8))
.build()?;
Ok(config
.lists
.into_iter()
.map(|list| {
let room_ids = if list.rooms.is_empty() {
&config.default_rooms
} else {
&list.rooms
}
.clone();
let list = list.clone();
let http_client = http_client.clone();
let matrix_client = matrix_client.clone();
let url = format!("https://www.mail-archive.com/{}/maillist.xml", list.name);
let state_file = config.state_dir.join(format!("{}.state", list.name));
let update_interval = Duration::from_secs(config.update_interval);
tokio::spawn(async move {
if !room_ids.is_empty() {
loop {
if let Err(err) =
handle_list(&list, &state_file, &http_client, &url, &matrix_client, &room_ids).await
{
warn!("{:#}", err);
}
sleep(update_interval).await;
}
}
})
})
.collect())
}
fn deser_rfc2616<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
where
D: de::Deserializer<'de>,
{
struct Rfc2616Visitor;
impl<'de> de::Visitor<'de> for Rfc2616Visitor {
type Value = DateTime<Utc>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an RFC2616-formatted datetime")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
dateparser::parse(v).map_err(E::custom)
}
}
deserializer.deserialize_any(Rfc2616Visitor)
}
#[cfg(test)]
mod test {
use std::{fs::File, io::BufReader};
use super::MailRss;
#[test]
pub fn test_feed_deser() -> anyhow::Result<()> {
let f = File::open(format!("{}/test-data/maillist.xml", env!("CARGO_MANIFEST_DIR")))?;
let r = BufReader::new(f);
let mail_rss = quick_xml::de::from_reader::<_, MailRss>(r)?;
println!("{:#?}", mail_rss);
Ok(())
}
}

View File

@ -22,226 +22,50 @@ extern crate log;
extern crate serde;
mod config;
mod event;
mod gitlab_event;
mod gitlab_webhook;
mod mail_archive;
mod matrix;
use std::{env, net::IpAddr, process::exit, sync::Arc, time::Duration};
use std::{env, net::IpAddr, process::exit};
use anyhow::Context;
use constant_time_eq::constant_time_eq;
use event::{GitlabEvent, GitlabEventExt};
use http::StatusCode;
use matrix_sdk::{
config::SyncSettings,
room::Joined,
ruma::{events::room::message::RoomMessageEventContent, OwnedRoomOrAliasId},
BaseRoom, Client,
};
use tokio::sync::mpsc;
use futures::future::join_all;
use warp::Filter;
async fn build_sync_settings(matrix_client: &Client) -> SyncSettings {
let mut settings = SyncSettings::default().timeout(Duration::from_secs(30));
if let Some(token) = matrix_client.sync_token().await {
settings = settings.token(token);
}
settings
}
async fn matrix_connect(config: &config::Config) -> anyhow::Result<Client> {
let client = Client::builder()
.server_name(config.user_id.server_name())
.user_agent(format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")))
.build()
.await?;
client
.login_username(&config.user_id, &config.password)
.initial_device_display_name("Bebot")
.send()
.await?;
info!("Connected to matrix as {}; waiting for first sync", config.user_id);
let settings = build_sync_settings(&client).await;
client.sync_once(settings).await?;
info!("First matrix sync complete");
let sync_client = client.clone();
tokio::spawn(async move {
let settings = build_sync_settings(&sync_client).await;
if let Err(err) = sync_client.sync(settings).await {
error!("Matrix sync failed: {}", err);
exit(1);
}
});
Ok(client)
}
async fn ensure_matrix_room_joined(matrix_client: &Client, room_id: &OwnedRoomOrAliasId) -> anyhow::Result<Joined> {
fn room_matches(a_room: &BaseRoom, our_room: &OwnedRoomOrAliasId) -> bool {
let our_room_str = our_room.as_str();
a_room.room_id().as_str() == our_room_str
|| a_room
.canonical_alias()
.iter()
.any(|alias| alias.as_str() == our_room_str)
|| a_room.alt_aliases().iter().any(|alias| alias.as_str() == our_room_str)
}
let mut room = matrix_client
.joined_rooms()
.iter()
.find(|a_room| room_matches(a_room, room_id))
.cloned();
if room.is_none() {
if let Some(invited) = matrix_client
.invited_rooms()
.iter()
.find(|a_room| room_matches(a_room, room_id))
{
invited.accept_invitation().await?;
} else {
matrix_client.join_room_by_id_or_alias(room_id, &[]).await?;
}
let settings = build_sync_settings(matrix_client).await;
matrix_client.sync_once(settings).await?;
room = matrix_client
.joined_rooms()
.iter()
.find(|a_room| room_matches(a_room, room_id))
.cloned();
}
room.ok_or_else(|| anyhow!("Unable to join room {}", room_id))
}
fn build_gitlab_messages(event: &GitlabEvent) -> Vec<String> {
let project = event.project();
let refname = event.r#ref().map(event::parse_ref);
event
.titles()
.iter()
.map(|title| {
format!(
"\\[{}\\] {}*{}* {}",
project.path_with_namespace,
refname
.as_ref()
.map(|rn| format!("`{}` ", rn))
.unwrap_or_else(|| "".to_string()),
event.user(),
title,
)
})
.collect()
}
async fn handle_gitlab_event(
event: GitlabEvent,
room_id: &OwnedRoomOrAliasId,
matrix_client: &Client,
) -> anyhow::Result<()> {
let room = ensure_matrix_room_joined(matrix_client, room_id).await?;
for msg in build_gitlab_messages(&event) {
debug!("Sending message to {}: {}", room_id, msg);
let msg_content = RoomMessageEventContent::text_markdown(&msg);
room.send(msg_content, None).await?;
}
Ok(())
}
async fn run() -> anyhow::Result<()> {
let config_path = env::args()
.nth(1)
.ok_or_else(|| anyhow!("Config file should be passed as only parameter"))?;
let config = Arc::new(config::load(config_path).await?);
let addr = config
.bind_address
.as_ref()
.cloned()
.unwrap_or_else(|| "127.0.0.1".to_string())
.parse::<IpAddr>()
.context("Failed to parse bind_address")?;
let port = config.bind_port.unwrap_or(3000);
let mut config = config::load(config_path).await?;
let matrix_client = matrix_connect(&config).await.context("Failed to connect to Matrix")?;
let matrix_client = matrix::connect(&config).await.context("Failed to connect to Matrix")?;
let (event_tx, mut event_rx) = mpsc::channel::<(GitlabEvent, OwnedRoomOrAliasId)>(100);
tokio::spawn(async move {
while let Some((event, room)) = event_rx.recv().await {
if let Err(err) = handle_gitlab_event(event, &room, &matrix_client).await {
warn!("Failed to handle payload: {}", err);
}
}
});
let gitlab_root_path = if let Some(url_prefix) = config.url_prefix.as_ref() {
url_prefix.split('/').fold(warp::any().boxed(), |last, segment| {
if segment.is_empty() {
last
} else {
last.and(warp::path(segment.to_string())).boxed()
}
})
let handles = if let Some(mail_archive) = config.mail_archive.take() {
mail_archive::start_polling(mail_archive, matrix_client.clone())?
} else {
warp::any().boxed()
vec![]
};
let gitlab = gitlab_root_path
.and(warp::path!("hooks" / "gitlab"))
.and(warp::post())
.and(warp::header::<String>("x-gitlab-token"))
.and(warp::body::json())
.then(move |token: String, event: event::GitlabEvent| {
let config = Arc::clone(&config);
let event_tx = event_tx.clone();
if let Some(gitlab_webhook) = config.gitlab_webhook.take() {
let gitlab = gitlab_webhook::build_route(gitlab_webhook, matrix_client.clone())?;
let routes = gitlab.with(warp::log("bebot"));
async move {
match event {
GitlabEvent::Other => {
warp::reply::with_status("Unsupported Gitlab event type", StatusCode::BAD_REQUEST)
}
_ => {
let project = event.project();
let config_key = project.web_url.replace("http://", "").replace("https://", "");
if let Some(repo_config) = config.repo_configs.get(&config_key) {
if !constant_time_eq(token.as_bytes(), repo_config.token.as_bytes()) {
warn!("Invalid token for repo '{}'", config_key);
warp::reply::with_status("Invalid token", StatusCode::FORBIDDEN)
} else {
debug!("payload: {:?}", event);
if let Some(room) = repo_config.room.as_ref().or(config.default_room.as_ref()) {
let publish_events = repo_config
.publish_events
.as_ref()
.or(config.default_publish_events.as_ref());
if publish_events.map(|ecs| event.should_publish(ecs)).unwrap_or(true) {
if let Err(err) = event_tx.send((event, room.clone())).await {
warn!("Failed to enqueue payload: {}", err);
}
}
warp::reply::with_status("OK", StatusCode::OK)
} else {
info!("Channel not configured for repo '{}'", config_key);
warp::reply::with_status(
"Matrix room not configured for repo",
StatusCode::NOT_FOUND,
)
}
}
} else {
info!("Repo '{}' unconfigured", config_key);
warp::reply::with_status("Repo not configured", StatusCode::NOT_FOUND)
}
}
}
}
});
let addr = config
.bind_address
.as_ref()
.cloned()
.unwrap_or_else(|| "127.0.0.1".to_string())
.parse::<IpAddr>()
.context("Failed to parse bind_address")?;
let port = config.bind_port.unwrap_or(3000);
warp::serve(routes).run((addr, port)).await;
}
let routes = gitlab.with(warp::log("bebot"));
join_all(handles).await;
warp::serve(routes).run((addr, port)).await;
Ok(())
error!("No functionality is configured; exiting");
exit(1);
}
#[tokio::main]
@ -252,7 +76,7 @@ async fn main() {
env_logger::init_from_env(lenv);
if let Err(err) = run().await {
error!("{}", err);
error!("{:#}", err);
exit(1);
}
}

188
src/matrix.rs Normal file
View File

@ -0,0 +1,188 @@
// bebot
// Copyright (C) 2023 Brian Tarricone <brian@tarricone.org>
//
// 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
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use std::{fmt, process::exit, time::Duration};
use matrix_sdk::{
config::SyncSettings,
room::Joined,
ruma::{OwnedRoomOrAliasId, OwnedUserId, RoomOrAliasId, UserId},
BaseRoom, Client,
};
use serde::de;
use crate::config::Config;
async fn build_sync_settings(matrix_client: &Client) -> SyncSettings {
let mut settings = SyncSettings::default().timeout(Duration::from_secs(30));
if let Some(token) = matrix_client.sync_token().await {
settings = settings.token(token);
}
settings
}
pub async fn connect(config: &Config) -> anyhow::Result<Client> {
let client = Client::builder()
.server_name(config.user_id.server_name())
.user_agent(format!("{}/{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")))
.build()
.await?;
client
.login_username(&config.user_id, &config.password)
.initial_device_display_name("Bebot")
.send()
.await?;
info!("Connected to matrix as {}; waiting for first sync", config.user_id);
let settings = build_sync_settings(&client).await;
client.sync_once(settings).await?;
info!("First matrix sync complete");
let sync_client = client.clone();
tokio::spawn(async move {
let settings = build_sync_settings(&sync_client).await;
if let Err(err) = sync_client.sync(settings).await {
error!("Matrix sync failed: {}", err);
exit(1);
}
});
Ok(client)
}
pub async fn ensure_room_joined(matrix_client: &Client, room_id: &OwnedRoomOrAliasId) -> anyhow::Result<Joined> {
fn room_matches(a_room: &BaseRoom, our_room: &OwnedRoomOrAliasId) -> bool {
let our_room_str = our_room.as_str();
a_room.room_id().as_str() == our_room_str
|| a_room
.canonical_alias()
.iter()
.any(|alias| alias.as_str() == our_room_str)
|| a_room.alt_aliases().iter().any(|alias| alias.as_str() == our_room_str)
}
let mut room = matrix_client
.joined_rooms()
.iter()
.find(|a_room| room_matches(a_room, room_id))
.cloned();
if room.is_none() {
if let Some(invited) = matrix_client
.invited_rooms()
.iter()
.find(|a_room| room_matches(a_room, room_id))
{
invited.accept_invitation().await?;
} else {
matrix_client.join_room_by_id_or_alias(room_id, &[]).await?;
}
let settings = build_sync_settings(matrix_client).await;
matrix_client.sync_once(settings).await?;
room = matrix_client
.joined_rooms()
.iter()
.find(|a_room| room_matches(a_room, room_id))
.cloned();
}
room.ok_or_else(|| anyhow!("Unable to join room {}", room_id))
}
pub fn deser_user_id<'de, D>(deserializer: D) -> Result<OwnedUserId, D::Error>
where
D: de::Deserializer<'de>,
{
struct UserIdVisitor;
impl<'de> de::Visitor<'de> for UserIdVisitor {
type Value = OwnedUserId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a matrix user ID")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
UserId::parse(v).map_err(E::custom)
}
}
deserializer.deserialize_any(UserIdVisitor)
}
fn deser_room_or_alias_id<'de, D>(deserializer: D) -> Result<OwnedRoomOrAliasId, D::Error>
where
D: de::Deserializer<'de>,
{
struct RoomOrAliasIdVisitor;
impl<'de> de::Visitor<'de> for RoomOrAliasIdVisitor {
type Value = OwnedRoomOrAliasId;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a matrix room ID")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
RoomOrAliasId::parse(v).map_err(E::custom)
}
}
deserializer.deserialize_any(RoomOrAliasIdVisitor)
}
pub fn deser_optional_room_or_alias_id<'de, D>(deserializer: D) -> Result<Option<OwnedRoomOrAliasId>, D::Error>
where
D: de::Deserializer<'de>,
{
struct OptionalRoomOrAliasIdVisitor;
impl<'de> de::Visitor<'de> for OptionalRoomOrAliasIdVisitor {
type Value = Option<OwnedRoomOrAliasId>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("null or matrix room ID")
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(None)
}
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(Some(deser_room_or_alias_id(deserializer)?))
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
RoomOrAliasId::parse(v).map(Some).map_err(E::custom)
}
}
deserializer.deserialize_any(OptionalRoomOrAliasIdVisitor)
}

722
test-data/maillist.xml Normal file
View File

@ -0,0 +1,722 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<!-- MHonArc v2.6.19+ -->
<channel>
<title>xfce-announce</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org</link>
<description>xfce-announce @ xfce</description>
<pubDate>Wed, 20 Sep 2023 00:05:30 GMT</pubDate>
<lastBuildDate>Wed, 20 Sep 2023 00:05:30 GMT</lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<generator>MHonArc RSS 2.0 RCFile</generator>
<webMaster>themailarchive@gmail.com (The Mail Archive)</webMaster>
<image>
<title>The Mail Archive</title>
<url>http://www.mail-archive.com/nanologo.png</url>
<link>http://www.mail-archive.com/xfce-announce@xfce.org</link>
</image>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.9.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00875.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/09/20&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Wed, 20 Sep 2023 00:05:29 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00875.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.9.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00874.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/09/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Mon, 18 Sep 2023 21:21:54 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00874.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-appfinder 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00873.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/09/08&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Andre Miranda%22"&gt;Andre Miranda&lt;/a&gt;</description>
<pubDate>Fri, 08 Sep 2023 21:21:14 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00873.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar 4.18.7 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00872.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/09/01&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Fri, 01 Sep 2023 22:48:46 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00872.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-whiskermenu-plugin 2.8.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00871.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/08/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Graeme Gott%22"&gt;Graeme Gott&lt;/a&gt;</description>
<pubDate>Tue, 29 Aug 2023 14:34:06 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00871.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-appfinder 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00870.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/08/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Andre Miranda%22"&gt;Andre Miranda&lt;/a&gt;</description>
<pubDate>Tue, 22 Aug 2023 19:37:53 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00870.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-terminal 1.1.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00869.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/08/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 22 Aug 2023 09:33:15 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00869.html</guid>
</item>
<item>
<title>ANNOUNCE: catfish 4.18.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00868.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/08/06&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sun, 06 Aug 2023 09:01:49 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00868.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-clipman-plugin 1.6.4 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00867.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/07/31&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 31 Jul 2023 13:56:43 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00867.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-volumed-pulse 0.2.4 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00866.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/07/25&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 25 Jul 2023 11:10:24 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00866.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-cpugraph-plugin 1.2.8 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00865.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/07/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Błażej Szczygieł%22"&gt;Błażej Szczygieł&lt;/a&gt;</description>
<pubDate>Sat, 22 Jul 2023 20:59:22 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00865.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-verve-plugin 2.0.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00864.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/07/15&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 15 Jul 2023 18:29:04 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00864.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-settings 4.18.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00863.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/07/04&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 04 Jul 2023 08:10:25 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00863.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-panel-profiles 1.0.14 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00862.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/06/05&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 05 Jun 2023 07:06:36 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00862.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-pulseaudio-plugin 0.4.7 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00861.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/06/01&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Błażej Szczygieł%22"&gt;Błażej Szczygieł&lt;/a&gt;</description>
<pubDate>Thu, 01 Jun 2023 11:41:25 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00861.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-screensaver 4.18.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00860.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/30&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 30 May 2023 08:01:59 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00860.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-power-manager 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00859.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/30&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 30 May 2023 07:56:50 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00859.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-power-manager 4.18.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00858.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/30&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 30 May 2023 07:47:19 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00858.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-session 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00857.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 29 May 2023 16:08:10 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00857.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4ui 4.19.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00856.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 29 May 2023 15:56:04 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00856.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-session 4.18.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00855.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 29 May 2023 15:49:40 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00855.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-generic-slider 1.0.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00854.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/26&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Fri, 26 May 2023 17:06:57 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00854.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-panel 4.18.4 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00853.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 22 May 2023 17:45:02 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00853.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4ui 4.18.4 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00852.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 22 May 2023 17:06:08 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00852.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-screenshooter 1.10.4 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00851.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/14&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Andre Miranda%22"&gt;Andre Miranda&lt;/a&gt;</description>
<pubDate>Sun, 14 May 2023 11:31:56 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00851.html</guid>
</item>
<item>
<title>ANNOUNCE: ristretto 0.13.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00850.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/13&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 13 May 2023 15:59:23 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00850.html</guid>
</item>
<item>
<title>ANNOUNCE: mousepad 0.6.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00849.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/13&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 13 May 2023 15:45:22 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00849.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4util 4.19.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00848.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/11&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 11 May 2023 14:14:17 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00848.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4util 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00847.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/07&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sun, 07 May 2023 08:39:15 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00847.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-mixer 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00846.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/05/01&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 01 May 2023 18:21:54 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00846.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar 4.18.6 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00845.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/30&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Sun, 30 Apr 2023 09:34:07 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00845.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-netload-plugin 1.4.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00844.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 29 Apr 2023 06:28:16 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00844.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-mpc-plugin 0.5.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00843.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 29 Apr 2023 06:24:59 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00843.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-mixer 4.18.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00842.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/29&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 29 Apr 2023 06:16:57 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00842.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar 4.18.5 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00841.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Fri, 28 Apr 2023 20:50:14 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00841.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-whiskermenu-plugin 2.7.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00840.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/26&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Graeme Gott%22"&gt;Graeme Gott&lt;/a&gt;</description>
<pubDate>Wed, 26 Apr 2023 11:25:21 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00840.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-dict 0.8.5 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00839.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 22 Apr 2023 14:59:42 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00839.html</guid>
</item>
<item>
<title>ANNOUNCE: xfmpc 0.3.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00838.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 22 Apr 2023 14:54:03 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00838.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-weather-plugin 0.11.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00837.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Fri, 21 Apr 2023 18:51:58 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00837.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-time-out-plugin 1.1.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00836.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Fri, 21 Apr 2023 17:27:47 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00836.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-indicator-plugin 2.4.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00835.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Fri, 21 Apr 2023 09:51:53 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00835.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-mount-plugin 1.1.6 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00834.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/20&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 20 Apr 2023 21:19:57 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00834.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4ui 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00833.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/20&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 20 Apr 2023 20:17:14 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00833.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-mailwatch-plugin 1.3.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00832.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/20&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 20 Apr 2023 18:43:40 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00832.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-fsguard-plugin 1.1.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00831.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/19&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Wed, 19 Apr 2023 17:30:01 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00831.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-calculator-plugin 0.7.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00830.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/19&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Wed, 19 Apr 2023 17:23:59 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00830.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-battery-plugin 1.1.5 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00829.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/19&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Wed, 19 Apr 2023 16:55:39 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00829.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-appfinder 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00828.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/19&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Andre Miranda%22"&gt;Andre Miranda&lt;/a&gt;</description>
<pubDate>Wed, 19 Apr 2023 16:34:38 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00828.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-timer-plugin 1.7.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00827.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 18 Apr 2023 16:03:44 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00827.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-power-manager 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00826.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 18 Apr 2023 15:08:59 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00826.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-session 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00825.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 18 Apr 2023 14:52:59 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00825.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-settings 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00824.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 18 Apr 2023 11:30:02 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00824.html</guid>
</item>
<item>
<title>ANNOUNCE: garcon 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00823.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 18 Apr 2023 11:18:13 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00823.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4ui 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00822.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 17 Apr 2023 14:22:29 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00822.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4util 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00821.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 17 Apr 2023 11:25:12 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00821.html</guid>
</item>
<item>
<title>ANNOUNCE: tumbler 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00820.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 17 Apr 2023 11:10:57 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00820.html</guid>
</item>
<item>
<title>ANNOUNCE: xfconf 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00819.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 17 Apr 2023 11:06:03 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00819.html</guid>
</item>
<item>
<title>ANNOUNCE: tumbler 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00818.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 17 Apr 2023 10:56:58 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00818.html</guid>
</item>
<item>
<title>ANNOUNCE: xfconf 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00817.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 17 Apr 2023 10:38:46 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00817.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-genmon-plugin 4.2.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00816.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/16&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Tony Paulic%22"&gt;Tony Paulic&lt;/a&gt;</description>
<pubDate>Sun, 16 Apr 2023 23:34:56 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00816.html</guid>
</item>
<item>
<title>ANNOUNCE: xfdesktop 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00815.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/04/14&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Fri, 14 Apr 2023 22:55:25 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00815.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar-archive-plugin 0.5.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00814.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/31&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Fri, 31 Mar 2023 21:18:14 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00814.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-panel 4.19.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00813.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 28 Mar 2023 19:08:27 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00813.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-pulseaudio-plugin 0.4.6 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00812.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 28 Mar 2023 19:05:50 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00812.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-panel 4.18.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00811.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 28 Mar 2023 17:57:50 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00811.html</guid>
</item>
<item>
<title>ANNOUNCE: garcon 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00810.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 28 Mar 2023 17:41:11 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00810.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4ui 4.18.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00809.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 28 Mar 2023 17:21:43 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00809.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-session 4.18.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00808.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 28 Mar 2023 17:13:19 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00808.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-screensaver 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00807.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/26&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sun, 26 Mar 2023 20:36:45 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00807.html</guid>
</item>
<item>
<title>Re: ANNOUNCE: xfce4-docklike-plugin 0.4.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00806.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Luna Jernberg%22"&gt;Luna Jernberg&lt;/a&gt;</description>
<pubDate>Tue, 21 Mar 2023 07:53:23 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00806.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-clipman-plugin 1.6.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00805.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/20&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Mon, 20 Mar 2023 20:07:46 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00805.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-docklike-plugin 0.4.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00804.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/19&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sun, 19 Mar 2023 16:41:45 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00804.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-screensaver 4.18.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00803.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 18 Mar 2023 10:47:52 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00803.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notes-plugin 1.10.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00802.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 18 Mar 2023 10:12:20 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00802.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-dev-tools 4.19.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00801.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/05&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Sun, 05 Mar 2023 08:52:26 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00801.html</guid>
</item>
<item>
<title>ANNOUNCE: xfburn 0.7.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00800.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/03/04&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Hunter Turcin%22"&gt;Hunter Turcin&lt;/a&gt;</description>
<pubDate>Sat, 04 Mar 2023 07:40:15 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00800.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.8.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00799.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/28&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Tue, 28 Feb 2023 06:39:12 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00799.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar 4.18.4 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00798.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Wed, 22 Feb 2023 21:57:16 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00798.html</guid>
</item>
<item>
<title>ANNOUNCE: parole 4.18.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00797.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/18&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 18 Feb 2023 19:39:06 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00797.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.8.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00796.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Fri, 17 Feb 2023 03:26:47 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00796.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-settings 4.18.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00795.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/11&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Sat, 11 Feb 2023 09:36:19 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00795.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.8.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00794.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/11&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Sat, 11 Feb 2023 07:51:19 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00794.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-power-manager 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00793.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/10&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Fri, 10 Feb 2023 10:23:06 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00793.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-session 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00792.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/10&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Fri, 10 Feb 2023 10:14:48 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00792.html</guid>
</item>
<item>
<title>ANNOUNCE: ristretto 0.13.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00791.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/09&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 09 Feb 2023 17:41:13 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00791.html</guid>
</item>
<item>
<title>ANNOUNCE: mousepad 0.6.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00790.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/09&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 09 Feb 2023 17:21:04 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00790.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-panel 4.18.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00789.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/09&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 09 Feb 2023 17:01:36 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00789.html</guid>
</item>
<item>
<title>ANNOUNCE: libxfce4ui 4.18.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00788.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/09&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Thu, 09 Feb 2023 11:06:57 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00788.html</guid>
</item>
<item>
<title>ANNOUNCE: orage 4.18.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00787.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/08&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Wed, 08 Feb 2023 16:21:58 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00787.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar-media-tags-plugin 0.4.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00786.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/06&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Mon, 06 Feb 2023 16:10:00 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00786.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.7.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00785.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/02/02&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Thu, 02 Feb 2023 03:07:52 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00785.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.7.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00784.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/22&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Sun, 22 Jan 2023 08:59:46 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00784.html</guid>
</item>
<item>
<title>ANNOUNCE: xfdesktop 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00783.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Sat, 21 Jan 2023 12:04:24 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00783.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.7.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00782.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Sat, 21 Jan 2023 11:50:36 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00782.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-notifyd 0.7.0 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00781.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/21&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Brian Tarricone%22"&gt;Brian Tarricone&lt;/a&gt;</description>
<pubDate>Sat, 21 Jan 2023 11:26:06 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00781.html</guid>
</item>
<item>
<title>ANNOUNCE: thunar 4.18.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00780.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/20&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Alexander Schwinn%22"&gt;Alexander Schwinn&lt;/a&gt;</description>
<pubDate>Fri, 20 Jan 2023 22:43:03 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00780.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-whiskermenu-plugin 2.7.2 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00779.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/17&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Graeme Gott%22"&gt;Graeme Gott&lt;/a&gt;</description>
<pubDate>Tue, 17 Jan 2023 18:24:47 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00779.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-datetime-plugin 0.8.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00778.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/16&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Andre Miranda%22"&gt;Andre Miranda&lt;/a&gt;</description>
<pubDate>Mon, 16 Jan 2023 21:21:48 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00778.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-screenshooter 1.10.3 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00777.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/12&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Andre Miranda%22"&gt;Andre Miranda&lt;/a&gt;</description>
<pubDate>Thu, 12 Jan 2023 23:19:39 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00777.html</guid>
</item>
<item>
<title>ANNOUNCE: xfce4-panel 4.18.1 released</title>
<link>http://www.mail-archive.com/xfce-announce@xfce.org/msg00776.html</link>
<description>&lt;font color=#6f6f6f&gt; 2023/01/10&lt;/font&gt; -- &lt;a href="http://www.mail-archive.com/search?l=xfce-announce@xfce.org&amp;q=from:%22Gaël Bonithon%22"&gt;Gaël Bonithon&lt;/a&gt;</description>
<pubDate>Tue, 10 Jan 2023 21:04:35 GMT</pubDate>
<guid isPermaLink="true">http://www.mail-archive.com/xfce-announce@xfce.org/msg00776.html</guid>
</item>
</channel>
</rss>
<!-- MHonArc v2.6.19+ -->