le dépôt central du wiki du C.A. (via un lien symbolique dans
 `.git/hooks/pre-receive`).
 
+update-ag-subscribers
+---------------------
+
+Met à jour la liste des emails inscrites à la liste ag@ par rapport aux membres
+à jour de cotisation. À exécuter à travers un *cron*. A besoin de pouvoir
+lancer les commandes `list_members`, `add_members` et `remove_members` via
+`sudo` sur le compte `list`.
+
 Développement
 =============
 
 
 Il faut ensuite mettre en place le lien symbolique vers le script
 `pre-receive-hooks`. XXX: à détailler
+
+XXX: configuration sudoers
+XXX: crontab pour update-ag-subscribers
 
 
 require 'nos_oignons/mailman'
 require 'nos_oignons/subscriptions'
+
+LIST = 'ag'
+
+current_emails = NosOignons::Mailman.list_members(LIST)
+uptodate_emails = NosOignons::Subscription.all.select(&:up_to_date?).collect(&:email)
+
+NosOignons::Mailman.add_members(LIST, uptodate_emails - current_emails)
+NosOignons::Mailman.remove_members(LIST, current_emails - uptodate_emails)
 
   write_file file, render_subscription_file(data)
 end
 
+Given /^une nouvelle adhésion de (\w+)$/ do |name|
+  data = { 'name' => name,
+           'address' => "At #{name}",
+           'email' => "#{name.downcase}@example.org",
+           'membership_fee_paid_on' => Time.now.strftime('%Y-%m-%d')
+         }
+  create_dir 'Membres'
+  file = subscription_filename_for_id(new_id)
+  write_file file, render_subscription_file(data)
+end
+
 When /^j'ajoute une fiche correcte pour une nouvelle adhésion$/ do
   @file = subscription_filename_for_id(new_id)
   write_file @file, render_subscription_file(EXTRA_SUBSCRIPTION)
 
--- /dev/null
+#!/bin/sh
+
+if ! [ "-u" = "$1" ] && ! [ "list" = "$2" ]; then
+       echo "Bad call" >&2
+       exit 1
+fi
+
+shift 2
+
+exec "$@"
 
     Et une base avec Pierre, à jour de cotisation
     Et avec Jane qui n'a pas payé sa cotisation cette année
     Et avec Fatima, à jour de cotisation
-    Et une nouvelle adhésion de Sean
     Lorsque j'exécute update-ag-subscribers
     Alors la liste ag@ doit avoir comme emails inscrits:
       """
       pierre@example.org
       fatima@example.org
       """
+
+  Scénario: Un ajout et une suppression
+    Soit une liste ag@ avec comme emails inscrits:
+      """
+      pierre@example.org
+      jane@example.org
+      """
+    Et une base avec Pierre, à jour de cotisation
+    Et avec Jane qui n'a pas payé sa cotisation cette année
+    Et une nouvelle adhésion de Sean
+    Lorsque j'exécute update-ag-subscribers
+    Alors la liste ag@ doit avoir comme emails inscrits:
+      """
+      pierre@example.org
+      sean@example.org
+      """
 
   module Mailman
     class << self
       def list_members(list)
-        `list_members #{Shellwords.escape(list)}`.split
+        `sudo -u list list_members #{Shellwords.escape(list)}`.strip.split
       end
 
       def add_member(list, email)
       end
 
       def add_members(list, emails)
-        # XXX IO.popen 
-        `add_members #{Shellwords.escape(list)}`.split
+        IO.popen(['sudo', '-u', 'list', 'add_members', '-r', '-', list], 'w') do |io|
+          emails.each do |email|
+            io.puts email
+          end
+        end
+      end
+
+      def remove_member(list, email)
+        remove_members(list, [email])
+      end
+
+      def remove_members(list, emails)
+        IO.popen(['sudo', '-u', 'list', 'remove_members', '-f', '-', list], 'w') do |io|
+          emails.each do |email|
+            io.puts email
+          end
+        end
       end
     end
   end