Update 2022-12-08 13:17 OpenBSD/amd64

This commit is contained in:
c0dev0id
2022-12-08 13:17:01 +01:00
parent bacc864a23
commit bfa921461c
18 changed files with 1111 additions and 0 deletions

200
.mutt/scripts/MIMEmbellish Executable file
View File

@@ -0,0 +1,200 @@
#!/usr/bin/env python3
import re
import sys
import email
import shlex
import mimetypes
import subprocess
import os.path
from copy import copy
from hashlib import md5
from email import charset
from email import encoders
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
from os.path import basename, splitext
charset.add_charset('utf-8', charset.SHORTEST, '8bit')
command = os.path.expanduser('~/.mutt/scripts/htmlize.sh ')
def make_alternative(message, part):
alternative = convert(part, 'html', command)
alternative.set_payload(alternative.get_payload())
return alternative
def make_replacement(message, part):
return convert(part, 'plain', command)
def convert(part, to_subtype, command):
payload = part.get_payload()
if isinstance(payload, str):
payload = payload.encode('utf-8')
else:
payload = part.get_payload(None, True)
if not isinstance(payload, bytes):
payload = payload.encode('utf-8')
process = subprocess.run(
shlex.split(command),
input=payload, stdout=subprocess.PIPE, check=True)
return MIMEText(process.stdout, to_subtype, 'utf-8')
def with_alternative(parent, part, from_signed,
make_alternative=make_alternative,
make_replacement=None):
try:
alternative = make_alternative(parent or part, from_signed or part)
replacement = (make_replacement(parent or part, part)
if from_signed is None and make_replacement is not None
else part)
except:
return parent or part
envelope = MIMEMultipart('alternative')
if parent is None:
for k, v in part.items():
if (k.lower() != 'mime-version'
and not k.lower().startswith('content-')):
envelope.add_header(k, v)
del part[k]
envelope.attach(replacement)
envelope.attach(alternative)
if parent is None:
return envelope
payload = parent.get_payload()
payload[payload.index(part)] = envelope
return parent
def tag_attachments(message):
if message.get_content_type() == 'multipart/mixed':
for part in message.get_payload():
if (part.get_content_maintype() in ['image']
and 'Content-ID' not in part):
filename = part.get_param('filename',
header='Content-Disposition')
if isinstance(filename, tuple):
filename = str(filename[2], filename[0] or 'us-ascii')
if filename:
filename = splitext(basename(filename))[0]
if filename:
part.add_header('Content-ID', '<{}>'.format(filename))
return message
def attachment_from_file_path(attachment_path):
try:
mime, encoding = mimetypes.guess_type(attachment_path, strict=False)
maintype, subtype = mime.split('/')
with open(attachment_path, 'rb') as payload:
attachment = MIMENonMultipart(maintype, subtype)
attachment.set_payload(payload.read())
encoders.encode_base64(attachment)
if encoding:
attachment.add_header('Content-Encoding', encoding)
return attachment
except:
return None
attachment_path_pattern = re.compile(r'\]\s*\(\s*file://(/[^)]*\S)\s*\)|'
r'\]\s*:\s*file://(/.*\S)\s*$',
re.MULTILINE)
def link_attachments(payload):
attached = []
attachments = []
def on_match(match):
if match.group(1):
attachment_path = match.group(1)
cid_fmt = '](cid:{})'
else:
attachment_path = match.group(2)
cid_fmt = ']: cid:{}'
attachment_id = md5(attachment_path.encode()).hexdigest()
if attachment_id in attached:
return cid_fmt.format(attachment_id)
attachment = attachment_from_file_path(attachment_path)
if attachment:
attachment.add_header('Content-ID', '<{}>'.format(attachment_id))
attachments.append(attachment)
attached.append(attachment_id)
return cid_fmt.format(attachment_id)
return match.group()
return attachments, attachment_path_pattern.sub(on_match, payload)
def with_local_attachments(parent, part, from_signed,
link_attachments=link_attachments):
if from_signed is None:
attachments, payload = link_attachments(part.get_payload())
part.set_payload(payload)
else:
attachments, payload = link_attachments(from_signed.get_payload())
from_signed = copy(from_signed)
from_signed.set_payload(payload)
if not attachments:
return parent, part, from_signed
if parent is None:
parent = MIMEMultipart('mixed')
for k, v in part.items():
if (k.lower() != 'mime-version'
and not k.lower().startswith('content-')):
parent.add_header(k, v)
del part[k]
parent.attach(part)
for attachment in attachments:
parent.attach(attachment)
return parent, part, from_signed
def is_target(part, target_subtypes):
return (part.get('Content-Disposition', 'inline') == 'inline'
and part.get_content_maintype() == 'text'
and part.get_content_subtype() in target_subtypes)
def pick_from_signed(part, target_subtypes):
for from_signed in part.get_payload():
if is_target(from_signed, target_subtypes):
return from_signed
def seek_target(message, target_subtypes=['plain', 'markdown']):
if message.is_multipart():
if message.get_content_type() == 'multipart/signed':
part = pick_from_signed(message, target_subtypes)
if part is not None:
return None, message, part
elif message.get_content_type() == 'multipart/mixed':
for part in message.get_payload():
if part.is_multipart():
if part.get_content_type() == 'multipart/signed':
from_signed = pick_from_signed(part, target_subtypes)
if from_signed is not None:
return message, part, from_signed
elif is_target(part, target_subtypes):
return message, part, None
else:
if is_target(message, target_subtypes):
return None, message, None
return None, None, None
def main():
try:
message = email.message_from_file(sys.stdin)
parent, part, from_signed = seek_target(message)
if (parent, part, from_signed) == (None, None, None):
return message
tag_attachments(message)
print(with_alternative(
*with_local_attachments(parent, part, from_signed)))
except (BrokenPipeError, KeyboardInterrupt):
pass
if __name__ == '__main__':
main()

8
.mutt/scripts/display-filter Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
cat - \
| sed 's|\[--\(.*unsupported.*\)--\]$|## Attachment:\1|g' \
| egrep -v '\[-- Attachment #1 --\]$' \
| egrep -v '\[-- Type.* --\]$' \
| fgrep -v "WARNING: We have NO indication" \
| cat -s

40
.mutt/scripts/htmlize.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/sh
# read stdin
content=$(cat)
content_safe=$(echo "$content"| sed -E 's/^(>+)/\1 /g ;
s/^(>+) /\1 /g ;
s|<|\&lt;|g ;
s|>|\&gt;|g ;
s|^\&gt;\&gt;\&gt;\&gt;\&gt;\&gt;|\&gt;\&gt;\&gt;\&gt;\&gt;</span><span style="color: x">\&gt;</span>|g ;
s|^\&gt;\&gt;\&gt;\&gt;\&gt;|\&gt;\&gt;\&gt;\&gt;</span><span style="color: gray">\&gt;</span>|g ;
s|^\&gt;\&gt;\&gt;\&gt;|\&gt;\&gt;\&gt;</span><span style="color: brown">\&gt;</span>|g ;
s|^\&gt;\&gt;\&gt;|\&gt;\&gt;</span><span style="color: green">\&gt;</span>|g ;
s|^\&gt;\&gt;|\&gt;<span style="color: orange">\&gt;</span>|g ;
s|^\&gt;|<span style="color: blue">\&gt;</span>|g ;
s|^----------.*|<span style="color: gray">&</span>| ;
s|^Sender: |<b>&</b>| ;
s|^Date: |<b>&</b>| ;
s|^To: |<b>&</b>| ;
s|^Cc: |<b>&</b>| ;
s|^Subject: |<b>&</b>| ;
s|^-- $|</font><font face="Arial" size="0.75" color="gray">--\&nbsp;|g ;
s|^Stefan Hagen$|<b>&</b>|g ;
s|^SAP SE Germany, Walldorf$|<b>&</b>|g')
# wrap html
echo '<html>'
echo ' <head>'
echo ' <meta charset="utf-8">'
echo ' <meta name="viewport" content="width=device-width, initial-scale=1">'
echo ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">'
echo ' <meta http-equiv="X-UA-Compatible" content="IE=edge">'
echo ' <title></title>'
echo ' </head>'
echo ' <body style="min-width: 74ch; color: black; font-size: 11; line-height: 1.6; font: 11, \"Calibri\"">'
echo ' <pre>'
echo ' <font size="3" face="Calibri">'
echo "$content_safe"
echo '</font>'
echo '</pre>'
echo '</body>'
echo '</html>'

5
.mutt/scripts/mu-find.sh Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/ksh
printf "MU Seach: "
read -r term
mu find --clearlinks --format=links --linksdir=~/.cache/mu/results $term

223
.mutt/scripts/mutt-ical.py Executable file
View File

@@ -0,0 +1,223 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
"""
This script is meant as a simple way to reply to ical invitations from mutt.
See README for instructions and LICENSE for licensing information.
"""
from __future__ import with_statement
__author__="Martin Sander"
__license__="MIT"
from tzlocal import get_localzone
import pytz
import vobject
import tempfile, time
import os, sys
import warnings
from datetime import date, datetime
from subprocess import Popen, PIPE
from getopt import gnu_getopt as getopt
timezone = get_localzone()
mutt="mutt"
usage="""
usage:
%s [OPTIONS] -e your@email.address filename.ics
OPTIONS:
-i interactive
-a accept
-d decline
-t tentatively accept
-c mutt_command
(accept is default, last one wins)
""" % sys.argv[0]
def del_if_present(dic, key):
if dic.has_key(key):
del dic[key]
def set_accept_state(attendees, state):
for attendee in attendees:
attendee.params['PARTSTAT'] = [unicode(state)]
for i in ["RSVP","ROLE","X-NUM-GUESTS","CUTYPE"]:
del_if_present(attendee.params,i)
return attendees
def get_accept_decline():
while True:
sys.stdout.write("\nAccept Invitation? [y/n/t/q]")
ans = sys.stdin.readline()
if ans.lower() == 'y\n':
return 'ACCEPTED'
elif ans.lower() == 'n\n':
return 'DECLINED'
elif ans.lower() == 't\n':
return 'TENTATIVE'
elif ans.lower() == 'q\n':
return ''
def get_answer(invitation):
# create
ans = vobject.newFromBehavior('vcalendar')
ans.add('method')
ans.method.value = "REPLY"
ans.add('vevent')
# just copy from invitation
for i in ["uid", "summary", "dtstart", "dtend", "organizer"]:
if invitation.vevent.contents.has_key(i):
ans.vevent.add( invitation.vevent.contents[i][0] )
# new timestamp
ans.vevent.add('dtstamp')
ans.vevent.dtstamp.value = datetime.utcnow().replace(
tzinfo = invitation.vevent.dtstamp.value.tzinfo)
return ans
def write_to_tempfile(ical):
tempdir = tempfile.mkdtemp()
icsfile = tempdir+"/event-reply.ics"
with open(icsfile,"w") as f:
f.write(ical.serialize())
return icsfile, tempdir
def get_mutt_command(ical, email_address, accept_decline, icsfile):
accept_decline = accept_decline.capitalize()
if ical.vevent.contents.has_key('organizer'):
if hasattr(ical.vevent.organizer,'EMAIL_param'):
sender = ical.vevent.organizer.EMAIL_param
else:
sender = ical.vevent.organizer.value.split(':')[1] #workaround for MS
else:
sender = "NO SENDER"
summary = ical.vevent.contents['summary'][0].value.encode()
command = [mutt, "-e", "my_hdr From: %s" % email_address, "-a", icsfile,
"-s", "%s: %s" % (accept_decline, summary), "--", sender]
#Uncomment the below line, and move it above the -s line to enable the wrapper
#"-e", 'set sendmail=\'ical_reply_sendmail_wrapper.sh\'',
return command
def execute(command, mailtext):
process = Popen(command, stdin=PIPE)
process.stdin.write(mailtext)
process.stdin.close()
result = None
while result is None:
result = process.poll()
time.sleep(.1)
if result != 0:
print "unable to send reply, subprocess exited with\
exit code %d\nPress return to continue" % result
sys.stdin.readline()
def openics(invitation_file):
with open(invitation_file) as f:
try:
with warnings.catch_warnings(): #vobject uses deprecated Exception stuff
warnings.simplefilter("ignore")
invitation = vobject.readOne(f, ignoreUnreadable=True)
except AttributeError:
invitation = vobject.readOne(f, ignoreUnreadable=True)
return invitation
def display(ical):
summary = ical.vevent.contents['summary'][0].value.encode()
if ical.vevent.contents.has_key('organizer'):
if hasattr(ical.vevent.organizer,'EMAIL_param'):
sender = ical.vevent.organizer.EMAIL_param
else:
sender = ical.vevent.organizer.value.split(':')[1] #workaround for MS
else:
sender = "NO SENDER"
if ical.vevent.contents.has_key('description'):
description = ical.vevent.contents['description'][0].value
else:
description = "NO DESCRIPTION"
if ical.vevent.contents.has_key('attendee'):
attendees = ical.vevent.contents['attendee']
else:
attendees = ""
sys.stdout.write("Start:\t" + ical.vevent.dtstart.value.astimezone(timezone).strftime('%Y-%m-%d %I:%M %p %Z') + "\n")
sys.stdout.write("End:\t" + ical.vevent.dtend.value.astimezone(timezone).strftime('%Y-%m-%d %I:%M %p %Z') + "\n")
sys.stdout.write("From:\t" + sender + "\n")
sys.stdout.write("Title:\t" + summary + "\n")
sys.stdout.write("To:\t")
for attendee in attendees:
if hasattr(attendee,'EMAIL_param'):
sys.stdout.write(attendee.CN_param + " <" + attendee.EMAIL_param + ">, ")
else:
sys.stdout.write(attendee.CN_param + " <" + attendee.value.split(':')[1] + ">, ") #workaround for MS
sys.stdout.write("\n\n")
sys.stdout.write(description + "\n")
if __name__=="__main__":
email_address = None
email_addresses = []
accept_decline = ''
opts, args=getopt(sys.argv[1:],"e:aidtc:")
if len(args) < 1:
sys.stderr.write(usage)
sys.exit(1)
invitation = openics(args[0])
#print(invitation)
display(invitation)
for opt,arg in opts:
if opt == '-e':
email_addresses = arg.split(',')
if opt == '-i':
accept_decline = get_accept_decline()
if opt == '-a':
accept_decline = 'ACCEPTED'
if opt == '-d':
accept_decline = 'DECLINED'
if opt == '-t':
accept_decline = 'TENTATIVE'
if opt == '-c':
mutt = arg
if accept_decline == '':
sys.exit(0)
ans = get_answer(invitation)
if invitation.vevent.contents.has_key('attendee'):
attendees = invitation.vevent.contents['attendee']
else:
attendees = ""
set_accept_state(attendees,accept_decline)
ans.vevent.add('attendee')
ans.vevent.attendee_list.pop()
flag = 1
for attendee in attendees:
if hasattr(attendee,'EMAIL_param'):
if attendee.EMAIL_param in email_addresses:
ans.vevent.attendee_list.append(attendee)
email_address = attendee.EMAIL_param
flag = 0
else:
if attendee.value.split(':')[1] in email_addresses:
ans.vevent.attendee_list.append(attendee)
email_address = attendee.value.split(':')[1]
flag = 0
if flag:
sys.stderr.write("Seems like you have not been invited to this event!\n")
sys.exit(1)
icsfile, tempdir = write_to_tempfile(ans)
mutt_command = get_mutt_command(ans, email_address, accept_decline, icsfile)
mailtext = "From: %s\n\n%s has %s" % (email_address, email_address, accept_decline.lower())
execute(mutt_command, mailtext)
os.remove(icsfile)
os.rmdir(tempdir)

20
.mutt/scripts/portpatch.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
strip=0
clear
printf '\n---------------------------------------------------------------------\n'
egrep '^Index|^RCS|^diff --git|^file +' "$1" | sed 's,/cvs,/usr,g'
printf '---------------------------------------------------------------------\n\n'
printf "Path for patch [/usr/ports]? "
read _path
[ -z "$_path" ] && _path=/usr/ports
egrep -q '^diff --git a/' "$1" && strip=1
#print "Trying to apply patch"
#qprint -d "$1" "$1.out"
doas patch -Ep"$strip" -d $_path < "$1"
cd $_path && ksh

26
.mutt/scripts/portpatch2.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/sh
# needs converters/qprint
# mutt: macro pager,attach ^S "<pipe-message>cat > /tmp/muttpatch.diff<enter><shell-escape>~/.mutt/scripts/portpatch2.sh /tmp/muttpatch.diff<enter>"
clear
printf '\n---------------------------------------------------------------------\n'
grep -E 'Subject: |^Index|^RCS|^diff --git|^file +|^[-+]{3} ' "${1}"
printf '---------------------------------------------------------------------\n\n'
printf "Apply patch on path [defaults to /usr/ports]? "
read -r _path
printf "Fix quoted-printable mangeled patch? [y/N]: "
read -r _qprint
case ${_qprint} in
[y|Y]) _catcmd="qprint -d"; ;;
*) _catcmd="cat"; ;;
esac
printf "Strip? [0]: "
read -r _strip
${_catcmd} "${1}" | doas patch -Ep${_strip:=0} -d ${_path:=/usr/ports}
cd ${_path} && doas su

2
.mutt/scripts/search-msgid.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
luakit "https://marc.info/?i=$(cat - | sed -n 's/^Message-ID: <\(.*\)>/\1/p')"

View File

@@ -0,0 +1,2 @@
#!/bin/sh
ssh sdk@mail.codevoid.de "/usr/sbin/sendmail -F 'Stefan Hagen' -f sh@codevoid.de -t"

View File

@@ -0,0 +1,2 @@
#!/bin/sh
ssh sdk@cvs.openbsd.org "/usr/sbin/sendmail -F 'Stefan Hagen' -f sdk@openbsd.org -t"

89
.mutt/scripts/vcal2text.pl Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/perl
# from: http://dollyfish.net.nz/projects/mutt-filters
# vcalendar-filter is a simple filter to give plain text representations of vcards
# Copyright (C) 2008 Martyn Smith
#
# 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/>.
# This script takes a simple VCALENDAR file as input on STDIN and produces a
# human readable text/plain representation of it on STDOUT
#
# It has been designed for use with mutt's auto_view config option, see the
# README file for more details
use strict;
use warnings;
use Data::ICal;
use Text::Autoformat;
my $body = eval { local $/ = undef; <> };
my $calendar = Data::ICal->new(data => $body);
# If parsing failed, try parsing as version 1.0
$calendar = Data::ICal->new(data => $body, vcal10 => 1) unless $calendar;
# If parsing failed, give up :-(
unless ( $calendar ) {
print "Unable to parse vcalendar: ", $calendar->error_message, "\n";
print $body;
exit 1;
}
foreach my $entry ( @{$calendar->{entries}} ) {
my $properties;
foreach my $property ( keys %{$entry->properties} ) {
next unless defined $entry->property($property);
$properties->{$property} = join(', ', map { $_->decoded_value } @{$entry->property($property)});
if ( $property eq 'description' ) {
$properties->{$property} = eval qq{"$properties->{$property}"};
$properties->{$property} = autoformat $properties->{$property}, {
all => 1,
left => 15,
};
$properties->{$property} =~ s/^\s*// if defined $properties->{$property};
}
elsif ( $property =~ m{ \A dt (?: start | end ) \z }xms ) {
if ( $properties->{$property} =~ m{ (\d\d\d\d)(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d) }xms ) {
$properties->{$property} = "$1-$2-$3 $4:$5";
}
}
}
if ( $entry->ical_entry_type eq 'VTIMEZONE' ) {
unless ( defined $properties->{tzid} and $properties->{tzid} =~ m{Pacific/Auckland} ) {
print "Timezone : ", $properties->{tzid}, "\n";
print "\n";
}
}
elsif ( $entry->ical_entry_type eq 'VEVENT' ) {
print '-' x 72, "\n";
foreach my $key ( qw(summary BR description BR location organizer dtstart dtend) ) {
if ( $key eq 'BR' ) {
print "\n";
next;
}
next unless defined $properties->{$key};
printf "%-12s: %s\n", ucfirst $key, $properties->{$key};
}
}
else {
print "WARNING: Unknown entry type: ", $entry->ical_entry_type, "\n";
}
}