2 Revīzijas cc000eb11a ... 4a4cf75f6d

Autors SHA1 Ziņojums Datums
  Distopico 4a4cf75f6d Version 0.7.1 9 mēneši atpakaļ
  Distopico cc000eb11a Version 0.7.1 9 mēneši atpakaļ
4 mainītis faili ar 238 papildinājumiem un 16 dzēšanām
  1. 3 2
      README.md
  2. 1 1
      docs/offlineimap-notify.md
  3. 215 0
      icon.svg
  4. 19 13
      offlineimap_notify.py

+ 3 - 2
README.md

@@ -8,7 +8,8 @@ Wrapper for add notification sending to OfflineIMAP.
 
 
 Run OfflineIMAP after adding notification sending to its UIs.  When an account
 Run OfflineIMAP after adding notification sending to its UIs.  When an account
 finishes syncing, messages synced to the local repository will be reported
 finishes syncing, messages synced to the local repository will be reported
-using D-Bus (through `notify2`) or a fallback notifier command.
+using D-Bus (through `notify-py`) or fallback `notifier` command from
+configuration file.
 
 
 ## Quick Start
 ## Quick Start
 
 
@@ -26,7 +27,7 @@ using D-Bus (through `notify2`) or a fallback notifier command.
 ## Requirements
 ## Requirements
 * Python 3.10.x
 * Python 3.10.x
 * OfflineIMAP
 * OfflineIMAP
-* [notifypy][notifypy] (Optional)
+* [notify-py][notifypy] (Optional)
 
 
 ## Usage
 ## Usage
 For configuration options and usage check [Docs](https://framagit.org/distopico/offlineimap-notify/-/blob/master/docs/offlineimap-notify.md)
 For configuration options and usage check [Docs](https://framagit.org/distopico/offlineimap-notify/-/blob/master/docs/offlineimap-notify.md)

+ 1 - 1
docs/offlineimap-notify.md

@@ -10,7 +10,7 @@ offlineimap-notify [*option*] ...
 
 
 Run OfflineIMAP after adding notification sending to its UIs.  When an account
 Run OfflineIMAP after adding notification sending to its UIs.  When an account
 finishes syncing, messages synced to the local repository will be reported
 finishes syncing, messages synced to the local repository will be reported
-using D-Bus (through [notifypy][notifypy]) or fallback `notifier` command from
+using D-Bus (through [notify-py][notifypy]) or fallback `notifier` command from
 configuration file.
 configuration file.
 
 
 ## Options
 ## Options

+ 215 - 0
icon.svg

@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   id="svg8"
+   version="1.1"
+   viewBox="0 0 52.916665 52.916668"
+   height="200"
+   width="200"
+   sodipodi:docname="icon.svg"
+   inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:dc="http://purl.org/dc/elements/1.1/">
+  <sodipodi:namedview
+     id="namedview1997"
+     pagecolor="#ffffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     showgrid="false"
+     inkscape:zoom="0.69738406"
+     inkscape:cx="-121.88406"
+     inkscape:cy="-10.754476"
+     inkscape:window-width="1916"
+     inkscape:window-height="1040"
+     inkscape:window-x="1920"
+     inkscape:window-y="20"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g1621" />
+  <title
+     id="title957">Simple Emial Icon</title>
+  <defs
+     id="defs2">
+    <filter
+       id="filter1427"
+       style="color-interpolation-filters:sRGB;">
+      <feFlood
+         id="feFlood1417"
+         result="flood"
+         flood-color="rgb(29,29,29)"
+         flood-opacity="0.501961" />
+      <feComposite
+         id="feComposite1419"
+         result="composite1"
+         operator="in"
+         in2="SourceGraphic"
+         in="flood" />
+      <feGaussianBlur
+         id="feGaussianBlur1421"
+         result="blur"
+         stdDeviation="1.2"
+         in="composite1" />
+      <feOffset
+         id="feOffset1423"
+         result="offset"
+         dy="0"
+         dx="1" />
+      <feComposite
+         id="feComposite1425"
+         result="composite2"
+         operator="over"
+         in2="offset"
+         in="SourceGraphic" />
+    </filter>
+    <filter
+       id="filter1427-7"
+       style="color-interpolation-filters:sRGB">
+      <feFlood
+         id="feFlood1417-8"
+         result="flood"
+         flood-color="rgb(29,29,29)"
+         flood-opacity="0.501961" />
+      <feComposite
+         id="feComposite1419-8"
+         result="composite1"
+         operator="in"
+         in2="SourceGraphic"
+         in="flood" />
+      <feGaussianBlur
+         id="feGaussianBlur1421-4"
+         result="blur"
+         stdDeviation="1.2"
+         in="composite1" />
+      <feOffset
+         id="feOffset1423-1"
+         result="offset"
+         dy="0"
+         dx="1" />
+      <feComposite
+         id="feComposite1425-2"
+         result="composite2"
+         operator="over"
+         in2="offset"
+         in="SourceGraphic" />
+    </filter>
+    <filter
+       id="filter1603"
+       style="color-interpolation-filters:sRGB;">
+      <feFlood
+         id="feFlood1593"
+         result="flood"
+         flood-color="rgb(29,29,29)"
+         flood-opacity="0.501961" />
+      <feComposite
+         id="feComposite1595"
+         result="composite1"
+         operator="in"
+         in2="SourceGraphic"
+         in="flood" />
+      <feGaussianBlur
+         id="feGaussianBlur1597"
+         result="blur"
+         stdDeviation="0.8"
+         in="composite1" />
+      <feOffset
+         id="feOffset1599"
+         result="offset"
+         dy="0"
+         dx="0.7" />
+      <feComposite
+         id="feComposite1601"
+         result="composite2"
+         operator="over"
+         in2="offset"
+         in="SourceGraphic" />
+    </filter>
+  </defs>
+  <metadata
+     id="metadata5">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>Simple Emial Icon</dc:title>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
+        <dc:date>Nov 05 2018</dc:date>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Distopico &lt;distopico@riseup.net&gt;</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>simple</rdf:li>
+            <rdf:li>email</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <dc:description>Simple Email Icon</dc:description>
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Distopico</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:requires
+           rdf:resource="http://creativecommons.org/ns#Notice" />
+        <cc:requires
+           rdf:resource="http://creativecommons.org/ns#Attribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://creativecommons.org/ns#ShareAlike" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="g1623"
+     transform="translate(0,-244.08332)"
+     style="display:inline">
+    <g
+       id="g1621"
+       transform="translate(0.19352928,0.76972034)">
+      <path
+         style="opacity:1;fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:3.8900702;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         d="M 179.82812,73.707031 A 99.297982,68.728551 0 0 1 98.929688,102.72852 99.297982,68.728551 0 0 1 18.708984,74.384766 v 77.884764 c 0,3.91737 3.152941,7.07227 7.070313,7.07227 H 172.75586 c 3.91737,0 7.07226,-3.1549 7.07226,-7.07227 z"
+         transform="matrix(0.26458333,0,0,0.26458333,0,244.08332)"
+         id="path1609" />
+      <path
+         transform="matrix(0.26458333,0,0,0.26458333,0,244.08332)"
+         id="path1611"
+         d="m 25.779297,34.839844 c -3.917372,0 -7.070313,3.154894 -7.070313,7.072265 V 52.892578 C 30.386799,76.679457 62.632927,92.68986 98.929688,92.722656 135.95526,92.71642 168.69902,76.092362 179.82812,51.650391 v -9.738282 c 0,-3.917371 -3.15489,-7.072265 -7.07226,-7.072265 z"
+         style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:3.89007;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         sodipodi:nodetypes="sscccsss" />
+      <path
+         id="path1613"
+         transform="matrix(0.26458333,0,0,0.26458333,0,244.08332)"
+         d="m 99.087891,59.023438 -29.619141,29.978515 0.0039,0.0039 a 84.842448,58.723229 0 0 0 29.457032,3.716797 84.842448,58.723229 0 0 0 29.906248,-3.849609 l 0.23047,-0.232422 z"
+         style="opacity:1;fill:#e6e6e6;fill-opacity:1;stroke:none;stroke-width:3.8900702;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <path
+         id="path1617"
+         d="m 18.708984,74.384766 v 77.884764 c 0,3.91737 3.152941,7.07227 7.070313,7.07227 h 1.039062 l 73.927731,-56.64844 a 99.297981,68.72855 0 0 1 -1.816402,0.0352 99.297981,68.72855 0 0 1 -80.220704,-28.343754 z"
+         style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:3.8900702;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         transform="matrix(0.26458333,0,0,0.26458333,0,244.08332)" />
+      <path
+         style="opacity:1;fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:1.02924776;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+         d="m 47.527457,263.75045 v 20.60701 c 0,1.03647 -0.834216,1.8712 -1.870687,1.8712 H 45.381852 L 25.821806,271.24043 a 26.27259,18.184429 0 0 0 0.48059,0.009 26.27259,18.184429 0 0 0 21.225061,-7.49928 z"
+         id="path1619" />
+    </g>
+  </g>
+</svg>

+ 19 - 13
offlineimap_notify.py

@@ -72,24 +72,29 @@ CONFIG_DEFAULTS = OrderedDict((
 def send_notification(ui, conf, summary, body):
 def send_notification(ui, conf, summary, body):
     appname = 'OfflineIMAP'
     appname = 'OfflineIMAP'
     category = 'email.arrived'
     category = 'email.arrived'
-    encode = functools.partial(unicode.encode, errors='replace')
+    icon = conf['icon']
+    urgency = conf['urgency']
+    timeout = conf['timeout']
+    encoding = locale.getpreferredencoding(False)
+
+    if not icon or not os.path.isfile(icon):
+        icon = os.path.join(os.getcwd(), 'icon.svg')
+
     try:
     try:
         notification = notifypy.Notify()
         notification = notifypy.Notify()
         notification.application_name = appname
         notification.application_name = appname
-        notification.title = encode(unicode(summary), 'utf-8')
-        notification.message = encode(unicode(body), 'utf-8')
-        notification.icon = icon.encode('utf-8')
-        notification.urgency = conf['urgency']
-        notification.timeout = conf['timeout']
+        notification.title = summary
+        notification.message = body
+        notification.icon = icon
+        notification.urgency = urgency
+        notification.timeout = timeout
         notification.send()
         notification.send()
-    except (NameError, RuntimeError):  # no notifypy or no notification service
+    except (NameError, RuntimeError) as e: # no notify-py or no notification service
         try:
         try:
             format_args = {'appname': appname, 'category': category,
             format_args = {'appname': appname, 'category': category,
-                           'summary': summary, 'body': body, 'icon': conf['icon'],
-                           'urgency': conf['urgency'], 'timeout': conf['timeout']}
-            encoding = locale.getpreferredencoding(False)
-            subprocess.call([encode(word.format(**format_args),
-                                    encoding)
+                           'summary': summary, 'body': body, 'icon': icon,
+                           'urgency': urgency, 'timeout': timeout}
+            subprocess.call([word.format(**format_args).encode(encoding)
                              for word in shlex.split(conf['notifier'])])
                              for word in shlex.split(conf['notifier'])])
         except ValueError as exc:
         except ValueError as exc:
             ui.error(exc, msg='While parsing fallback notifier command')
             ui.error(exc, msg='While parsing fallback notifier command')
@@ -219,11 +224,12 @@ def notify(ui, account):
 
 
     need_body = '{body' in conf['body'] or '{body' in conf['summary']
     need_body = '{body' in conf['body'] or '{body' in conf['summary']
     parser = email.parser.Parser()
     parser = email.parser.Parser()
+    encoding = locale.getpreferredencoding(False)
     for folder, contents in ui.new_messages[account].items():
     for folder, contents in ui.new_messages[account].items():
         format_args = {'account': account_name,
         format_args = {'account': account_name,
                        'folder': folder}
                        'folder': folder}
         for content in contents:
         for content in contents:
-            message = parser.parsestr(content.get('message'),
+            message = parser.parsestr(content.get('message').as_string(),
                                       headersonly=not need_body)
                                       headersonly=not need_body)
             format_args['h'] = HeaderDecoder(message, failstr=conf['failstr'])
             format_args['h'] = HeaderDecoder(message, failstr=conf['failstr'])
             if need_body:
             if need_body: