]> gitweb.fluxo.info Git - firma.git/commitdiff
desfazendo a ultima merda, hoje tah foda
authorrhatto <rhatto>
Sat, 6 Aug 2005 16:45:53 +0000 (16:45 +0000)
committerrhatto <rhatto>
Sat, 6 Aug 2005 16:45:53 +0000 (16:45 +0000)
firma

diff --git a/firma b/firma
index 1fbb2b01e61a3ee7641cfba076930dcc08cc946d..6326362b96b18ecd335db9a4c8350599e537abf0 100755 (executable)
--- a/firma
+++ b/firma
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html
-       PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en   ">
-
-  <head>
-       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-       <title>codecoop: Exiting with error</title>
-       <link rel="alternate" title="codecoop - Project News Highlights RSS" href="/export/rss_sfnews.php" type="application/rss+xml"/>
-       <link rel="alternate" title="codecoop - New Projects RSS" href="/export/rss_sfprojects.php" type="application/rss+xml"/>
-
-       <script language="JavaScript" type="text/javascript">
-       <!--
-
-       function admin_window(adminurl) {
-               AdminWin = window.open( adminurl, 'AdminWindow','scrollbars=yes,resizable=yes, toolbar=yes, height=400, width=400, top=2, left=2');
-               AdminWin.focus();
-       }
-       function help_window(helpurl) {
-               HelpWin = window.open( helpurl,'HelpWindow','scrollbars=yes,resizable=yes,toolbar=no,height=400,width=400');
-       }
-       // -->
-               </script>
-
-<style type="text/css">
-       <!--
-       BODY {
-               margin-top: 3;
-               margin-left: 3;
-               margin-right: 3;
-               margin-bottom: 3;
-               background-image: url("/themes/gforge/images/theme-top-blue.png");
-       }
-       ol,ul,p,body,td,tr,th,form { font-family: verdana,arial,helvetica,sans-serif; font-size:small;
-               color: #333333; }
-
-       h1 { font-size: x-large; font-family: verdana,arial,helvetica,sans-serif; }
-       h2 { font-size: large; font-family: verdana,arial,helvetica,sans-serif; }
-       h3 { font-size: medium; font-family: verdana,arial,helvetica,sans-serif; }
-       h4 { font-size: small; font-family: verdana,arial,helvetica,sans-serif; }
-       h5 { font-size: x-small; font-family: verdana,arial,helvetica,sans-serif; }
-       h6 { font-size: xx-small; font-family: verdana,arial,helvetica,sans-serif; }
-
-       pre,tt { font-family: courier,sans-serif }
-
-       a:link { text-decoration:none; color: #0000be }
-       a:visited { text-decoration:none; color: #0000be }
-       a:active { text-decoration:none }
-       a:hover { text-decoration:underline; color:red }
-
-       .titlebar { color: black; text-decoration: none; font-weight: bold; }
-       a.tablink { color: black; text-decoration: none; font-weight: bold; font-size: x-small; }
-       a.tablink:visited { color: black; text-decoration: none; font-weight: bold; font-size: x-small; }
-       a.tablink:hover { text-decoration: none; color: black; font-weight: bold; font-size: x-small; }
-       a.tabsellink { color: #0000be; text-decoration: none; font-weight: bold; font-size: x-small; }
-       a.tabsellink:visited { color: #0000be; text-decoration: none; font-weight: bold; font-size: x-small; }
-       a.tabsellink:hover { text-decoration: none; color: #0000be; font-weight: bold; font-size: x-small; }
-               -->
-</style>
-<link rel="stylesheet" type="text/css" href="/plugins/scmcvs/cvsweb/css/cvsweb.css" /></head>
-
-<body>
-
-<table border="0" width="100%" cellspacing="0" cellpadding="0">
-
-       <tr>
-               <td><a href="/"><img src="/themes/gforge/images/logo.png" border="0" alt="" width="198" height="52" /></a></td>
-               <td>
-               <form action="/search/" method="get">
-               <table border="0" cellpadding="0" cellspacing="0">
-               <tr><td>
-               <div align="center" style="font-size:smaller"><select name="type_of_search"><option value="soft">Software/Group</option>
-<option value="people">People</option>
-<option value="skill">Skill</option>
-</select></div></td><td>&nbsp;</td><td><input type="text" size="12" name="words" value="" /></td><td>&nbsp;</td><td><input type="submit" name="Search" value="Search" /></td></tr></table></form></td>
-               <td align="right">                              <b><a style="color: #FFFFFF" href="/account/login.php">Log In</a></b><br />
-                               <b><a style="color: #FFFFFF" href="/account/register.php">New Account</a></b>
-                               </td>
-               <td>&nbsp;&nbsp;</td>
-       </tr>
-
-</table>
-
-<table border="0" width="100%" cellspacing="0" cellpadding="0">
-
-       <tr>
-               <td>&nbsp;</td>
-               <td colspan="3">
-
-
-
-               <!-- start tabs -->
-
-               <table border="0" cellpadding="0" cellspacing="0" width="100%">
-               <tr>
-                                       <td valign="top" width="10" background="/themes/gforge/images/theme-toptab-end-selected.png"><img src="/themes/gforge/images/clear.png" height="25" width="10" alt="" /></td><td background="/themes/gforge/images/theme-toptab-selected-bg.png" width="25%" align="center"><a class="tabsellink" href="/">Home</a></td>
-                                       <td colspan="2" valign="top" width="20" background="/themes/gforge/images/theme-toptab-selected-notselected.png"><img src="/themes/gforge/images/clear.png" height="2" width="20" alt="" /></td><td background="/themes/gforge/images/theme-toptab-notselected-bg.png" width="25%" align="center"><a class="tablink" href="/my/">My&nbsp;Page</a></td>
-                                       <td colspan="2" valign="top" width="20" background="/themes/gforge/images/theme-toptab-notselected-notselected.png"><img src="/themes/gforge/images/clear.png" height="2" width="20" alt="" /></td><td background="/themes/gforge/images/theme-toptab-notselected-bg.png" width="25%" align="center"><a class="tablink" href="/softwaremap/">Project&nbsp;Tree</a></td>
-                                       <td colspan="2" valign="top" width="20" background="/themes/gforge/images/theme-toptab-notselected-notselected.png"><img src="/themes/gforge/images/clear.png" height="2" width="20" alt="" /></td><td background="/themes/gforge/images/theme-toptab-notselected-bg.png" width="25%" align="center"><a class="tablink" href="/people/">Project&nbsp;Openings</a></td>
-                                       <td valign="top" width="10" background="/themes/gforge/images/theme-toptab-notselected-end.png"><img src="/themes/gforge/images/clear.png" height="2" width="10" alt="" /></td></tr><tr><td colspan="3" height="1" bgcolor="#e0e0e0"><img src="/themes/gforge/images/clear.png" height="1" width="10" /></td><td colspan="9" height="1" bgcolor="#909090"><img src="/themes/gforge/images/clear.png" height="1" width="10" /></td></tr>
-               </table> 
-
-               <!-- end tabs -->
-
-               </td>
-               <td>&nbsp;</td>
-       </tr>
-
-       <tr>
-               <td align="left" bgcolor="#E0E0E0" width="9"><img src="/themes/gforge/images/tabs/topleft.png" height="9" width="9" alt="" /></td>
-               <td bgcolor="#E0E0E0" width="30"><img src="/themes/gforge/images/clear.png" width="30" height="1" alt="" /></td>
-               <td bgcolor="#E0E0E0"><img src="/themes/gforge/images/clear.png" width="1" height="1" alt="" /></td>
-               <td bgcolor="#E0E0E0" width="30"><img src="/themes/gforge/images/clear.png" width="30" height="1" alt="" /></td>
-               <td align="right" bgcolor="#E0E0E0" width="9"><img src="/themes/gforge/images/tabs/topright.png" height="9" width="9" alt="" /></td>
-       </tr>
-
-       <tr>
-
-               <!-- Outer body row -->
-
-               <td bgcolor="#E0E0E0"><img src="/themes/gforge/images/clear.png" width="10" height="1" alt="" /></td>
-               <td valign="top" width="99%" bgcolor="#E0E0E0" colspan="3">
-
-                       <!-- Inner Tabs / Shell -->
-
-                       <table border="0" width="100%" cellspacing="0" cellpadding="0">
-                       <tr>
-                               <td align="left" bgcolor="#ffffff" width="9"><img src="/themes/gforge/images/tabs/topleft-inner.png" height="9" width="9" alt="" /></td>
-                               <td bgcolor="#ffffff"><img src="/themes/gforge/images/clear.png" width="1" height="1" alt="" /></td>
-                               <td align="right" bgcolor="#ffffff" width="9"><img src="/themes/gforge/images/tabs/topright-inner.png" height="9" width="9" alt="" /></td>
-                       </tr>
-
-                       <tr>
-                               <td bgcolor="#ffffff"><img src="/themes/gforge/images/clear.png" width="10" height="1" alt="" /></td>
-                               <td valign="top" width="99%" bgcolor="white">
-
-       <h2><span style="color:#FF3333">ERROR - No group_id was chosen</span></h2><p>No group Id was chosen</p>
-                       <!-- end main body row -->
-
-
-                               </td>
-                               <td width="10" bgcolor="#ffffff"><img src="/themes/gforge/images/clear.png" width="2" height="1" alt="" /></td>
-                       </tr>
-                       <tr>
-                               <td align="left" bgcolor="#E0E0E0" width="9"><img src="/themes/gforge/images/tabs/bottomleft-inner.png" height="11" width="11" alt="" /></td>
-                               <td bgcolor="#ffffff"><img src="/themes/gforge/images/clear.png" width="1" height="1" alt="" /></td>
-                               <td align="right" bgcolor="#E0E0E0" width="9"><img src="/themes/gforge/images/tabs/bottomright-inner.png" height="11" width="11" alt="" /></td>
-                       </tr>
-                       </table>
-
-               <!-- end inner body row -->
-
-               </td>
-               <td width="10" bgcolor="#E0E0E0"><img src="/themes/gforge/images/clear.png" width="2" height="1" alt="" /></td>
-       </tr>
-       <tr>
-               <td align="left" bgcolor="#E0E0E0" width="9"><img src="/themes/gforge/images/tabs/bottomleft.png" height="9" width="9" alt="" /></td>
-               <td bgcolor="#E0E0E0" colspan="3"><img src="/themes/gforge/images/clear.png" width="1" height="1" alt="" /></td>
-               <td align="right" bgcolor="#E0E0E0" width="9"><img src="/themes/gforge/images/tabs/bottomright.png" height="9" width="9" alt="" /></td>
-       </tr>
-</table>
-
-<!-- PLEASE LEAVE "Powered By GForge" on your site -->
-<br />
-<center>
-<a href="http://gforge.org/"><img src="/images/pow-gforge.png" alt="Powered By GForge Collaborative Development Environment" border="0" /></a>
-</center>
-
-
-</body>
-</html>
+#!/bin/bash
+#
+# firma: encrypted mailing list manager
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+#
+
+FIRMA_LIST_PATH="/usr/local/etc/lists"
+VERSION="0.3"
+
+# todo:
+# errase all vars before quit the game
+# unset MESSAGE
+# unset GPG_MESSAGE
+# umask ....
+
+function usage {
+  echo "usage: $(basename $0) OPTION [LIST-NAME]"
+  echo "  -a: admin commands"
+  echo "  -c: create a new list"
+  echo "  -h: display this help and exit"
+  echo "  -p: process a message"
+  echo "  -r: admin and user requests (mail only)"
+  echo "  -v: output version information and exit"
+}
+
+function version {
+  echo "firma $VERSION"
+  echo "Copyright (C) 2005 A Firma, Inc."
+  echo "This program comes with ABSOLUTELY NO WARRANTY."
+  echo "This is free software, and you are welcome to redistribute it"
+  echo "under certain conditions. See the GNU General Public License"
+  echo "for more details."
+}
+
+
+function check_config {
+  # check configuration file parameters
+  if [ ! -f $GPG -o ! -x $GPG ]; then
+    echo "$CONFIG_FILE: GPG binary ($GPG) could not be found."
+    exit 1
+  elif [ ! -f $MAIL -o ! -x $MAIL ]; then
+    echo "$CONFIG_FILE: Mail program ($MAIL) could not be found."
+    exit 1
+  elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then
+    echo "$CONFIG_FILE: GPG home directory ($GPGDIR) or the GPG keyrings could not be found."
+      exit 1
+  elif [ -z "$(cat $CONFIG | grep -o ^PASSWD=\'[^\']*\'$)" -o \
+         -z "$(echo -n $PASSWD)" -o \
+         "$(echo -n $PASSWD | wc -m)" -lt "25" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:lower:][:upper:]])" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:digit:]])" -o \
+         "$(echo -n $PASSWD | grep -o [[:punct:]] | wc -l)" -lt "5" ]; then
+    echo "$CONFIG_FILE: PASSWD is empty or does not meet the minimum complexity requirements."
+    echo "$CONFIG_FILE: Please set a new passphrase for the list's private key. Make it at least"
+    echo "$CONFIG_FILE: 25 characters long (using a combination of letters, numbers and at least"
+    echo "$CONFIG_FILE: 5 special characters) and enclose it in 'single quotes'. The passphrase"
+    echo "$CONFIG_FILE: itself, though, cannot contain any single quote."
+    exit 1
+  elif [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$LISTNAME\>$)" ]; then
+    echo "$CONFIG_FILE: GPG key for list \"$LISTNAME\" could not be found."
+    echo "$CONFIG_FILE: Note that this parameter expects an email address."
+    exit 1
+  else
+    for ADMIN in $LISTADMIN; do {
+      if [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$ADMIN\>$)" ]; then
+        echo "$CONFIG_FILE: GPG key for list administrator \"$ADMIN\" could not be found."
+        echo "$CONFIG_FILE: Note that this parameter expects one or more space separated email addresses."
+        exit 1
+      fi; }
+    done
+  fi
+}
+
+function get_gpg_stderr {
+  # discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+  echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | sed -e 's/^ //' | ($GPGDECRYPT --status-fd 2 1> /dev/null) 2>&1
+}
+
+function get_subscribers_list {
+  # get list susbscriber's addresses
+  $GPGLIST | sed -ne "/$LISTNAME/Id" -e '/pub/p' | cut -d : -f 10 | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g'
+}
+
+function get_message {
+  n=0
+  while read STDIN; do
+    MESSAGE[$n]="$STDIN\n"
+    ((++n))
+  done
+}
+
+function get_gpg_message {
+  signal=0
+  x=0
+  for ((count=0;count<=n;count++)); do
+    if [[ $signal == "0" ]] && [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----BEGIN PGP MESSAGE-----")" == "" ]]; then
+      GPG_MESSAGE[$x]=${MESSAGE[$count]}
+      ((++x))
+      signal=1
+    elif [[ $signal == "1" ]]; then
+      GPG_MESSAGE[$x]=${MESSAGE[$count]}
+      ((++x))
+      if [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----END PGP MESSAGE-----")" == "" ]]; then
+        signal=0
+      fi
+    fi
+  done
+}
+
+function get_message_headers {
+  # get the message headers and the sender's email address
+  FROM=$(echo -e "${MESSAGE[@]}" | grep -m 1 "From:" | cut -d : -f 2- | sed -e 's/^ //')
+  FROMADD=$(
+    if [ -z "$(echo $FROM | grep '>$')" ]; then
+      echo $FROM
+    else
+      echo $FROM | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g'
+    fi
+  )
+  DATE=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Date:" | sed -e 's/^ //')
+  SUBJECT=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Subject:" | cut -d : -f 2- | sed -e 's/^ //')
+}
+
+function message_list {
+# compose and send a message to the list
+# $1: subscriber email
+# sorry no identation :P  
+echo "$PASSWD
+Message from: $FROM
+Subject: $SUBJECT
+$DATE
+  
+$(get_gpg_stderr | grep -F 'gpg: Signature made')
+$(get_gpg_stderr | grep -F 'gpg: Good signature from')
+  
+$(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $1 | $MAIL -r $LISTNAME $1
+}
+
+function message_list_error {
+# compose and send an error message
+# sorry no identation :P  
+echo "$PASSWD
+Message from: $FROM
+Subject: [BAD SIGNATURE] $SUBJECT
+$DATE
+  
+$(get_gpg_stderr | grep -F 'gpg: Signature made')
+$(get_gpg_stderr | grep -F 'gpg: BAD signature from')
+$(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $1 | $MAIL -r $LISTNAME $1
+}
+
+function message_list_return {
+# send a bounce message
+# $1: sender email (usually $FROMADD)
+# sorry no identation :P  
+echo "
+Message from: $FROM
+Subject: [RETURNED MAIL] $SUBJECT
+$DATE
+  
+  [ It was not possible to process this message. Either or both
+    the message was not encrypted and/or signed, or you are not
+    subscribed to this list.  Contact the list administrator if
+    you have any questions. ]
+  -- 
+  firma v$VERSION" | $MAIL -r $LISTNAME $1
+}
+
+function process_message {
+  # process a message sent to the list
+
+  get_message
+  get_message_headers 
+  get_gpg_message
+
+  # if signature is Good, encrypt and send it for each list subscriber
+  # todo: declare a function to decrypt, re-encrypt and send the list messages
+  if (get_gpg_stderr | grep -Fq GOODSIG); then
+  
+    for EMAIL in $(get_subscribers_list); do 
+      message_list $EMAIL
+    done
+  
+  # else, if signature is BAD, email it back to the list admins and to sender
+  elif (get_gpg_stderr | grep -Fq BADSIG) ; then
+  
+    for EMAIL in $(echo $LISTADMIN $FROMADD); do
+      message_list_error $EMAIL
+    done
+  
+  # else, probably either the message was not signed or the sender is not subscribed to the list
+  # email the message back to sender including a note about this
+  # todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+  else
+    message_list_return $FROMADD 
+  fi
+   
+}
+
+function newlist {
+  # create a list if it doesnt already exist
+  if [ ! -d "$CONFIG_PATH" ]; then
+    echo creating folder $CONFIG_PATH...
+    mkdir "$CONFIG_PATH" # || (echo "error creating $CONFIG_PATH: installation aborted"; exit 1)
+    echo "creating list config file and will ask some questions."
+
+    read -p "path to nail command (eg, /usr/bin/nail): " MAIL
+    read -p "path to gpg binary (eg, /usr/bin/gpg): " GPG
+
+    # if [ ! -x $GPG ]; then 
+
+    read -p "list keyring folder (defaults to $GPGDIR): " GPGDIR
+
+    # todo: please no utf-8 (see DETAILS)
+    read -p "list email (eg, firma@domain.tld): " LISTNAME
+    read -p "list admins emails (space delimited): " LISTADMIN
+    read -p "list description (fake?): " DESCRIPTION
+    read -p "password for list keyring (use a huge one): " PASSWD 
+
+    # todo: key specs (size, expiry date...)
+
+    echo "creating your config..."
+    touch $CONFIG
+    chown root.root $CONFIG
+    chmod 600 $CONFIG
+    if [ -f $CONFIG ]; then
+      gpg_args
+      echo -e "MAIL=$MAIL\nGPG=$GPG\nGPGDIR=$GPGDIR\nLISTNAME=$LISTNAME\nLISTADMIN=$LISTADMIN\nPASSWD=$PASSWD" > $CONFIG
+      echo "now generating your keyring..."
+
+      $GPGCOMMAND --gen-key <<EOF
+
+        Key-Type: DSA
+        Key-Length: 1024
+        Subkey-Type: ELG-E
+        Subkey-Length: 1024
+
+        Name-Real: $DESCRIPTION 
+        Name-Email: $LISTNAME
+
+        Expire-Date: 0
+        Passphrase: $PASSWD
+        %commit
+
+EOF
+
+    fi
+  else
+    echo error creating $CONFIG_FILE: list already exists
+    exit 1 
+  fi
+}
+
+function gpg_args {
+  # declare GPG variables
+  GPGFLAGS="--quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+  GPGCOMMAND="$GPG $GPGFLAGS"
+  GPGLIST="$GPGCOMMAND --list-keys --with-colons"
+  GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+  GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient"
+}
+
+function list_admin {
+  if [ "$1" = "use" ]; then
+    if [ "$#" -lt "2" ]; then
+      echo "$(basename $0): Too few arguments. Command \"use\" expects an email address as argument."
+      return 1
+    elif [ "$#" -gt "2" ]; then
+      echo "$(basename $0): Too many arguments. Command \"use\" expects just one email address as argument."
+      return 1
+    elif [ -z "$(echo -ne $2 | grep -o '[^@]\+@[^@]\+')" ]; then
+      echo "$(basename $0): Invalid argument. Command \"use\" expects an email address as argument."
+      return 1
+    else
+      choose_uid $2
+    fi
+  else
+    echo "$(basename $0): \"$1\": command not found"
+  fi
+}
+
+function choose_uid {
+
+  KEYID="$($GPGLIST --fixed-list-mode $1 2> /dev/null | grep ^pub | cut -d : -f 5 | grep -o '.\{8\}$')"
+
+  if [ -z "$($GPGLIST --fingerprint --fixed-list-mode $1 2> /dev/null | grep -i \<$1\>:$ | cut -d : -f 10)" ]; then
+    echo "$CONFIG_FILE: \"$(echo -ne $1 | tr A-Z a-z)\" is not associated with any public key on this keyring."
+    return 1
+  elif [ "$($GPGLIST --fixed-list-mode $1 2> /dev/null | grep ^uid | wc -l)" -eq "1" ]; then
+    echo "$CONFIG_FILE: \"$(echo -ne $1 | tr A-Z a-z)\" is part of the only UID on public key \"$KEYID\"."
+    return 1
+  elif [ "$($GPGLIST --fixed-list-mode $1 2> /dev/null | grep -iF $1 | cut -d : -f 10 | wc -l)" -gt "1" ]; then
+    echo "$CONFIG_FILE: \"$(echo -ne $1 | tr A-Z a-z)\" is listed in more than one UID on this keyring. Narrow down your selection"
+    echo "$CONFIG_FILE: or delete all but one of the public keys associated with this email address."
+    return 1
+  fi
+
+  expect -nN -- << EOF
+    log_user 0
+    set timeout 5
+
+    set keyid [eval exec $GPG --fingerprint --with-colons --fixed-list-mode $1 | grep ^fpr | cut -d : -f 10]
+    set uid_count [eval exec $GPG --list-keys --with-colons --fixed-list-mode \$keyid | grep ^uid | wc -l]
+    set chosen_uid [eval exec $GPG --list-keys --with-colons --fixed-list-mode \$keyid | grep ^uid | grep -ni $1 | cut -d : -f 1]
+
+    eval spawn -noecho $GPG --with-colons --command-fd 0 --status-fd 1 --edit-key \$keyid
+    expect "GET_LINE keyedit.prompt" {
+      set uid 1
+      while { \$uid <= \$uid_count } {
+        if { \$uid != \$chosen_uid } {
+          send "uid \$uid\n"
+          expect "GET_LINE keyedit.prompt"
+        }
+        set uid [incr uid]
+      }
+      send "deluid\n"
+      expect "GET_BOOL keyedit.remove.uid.okay" {send "yes\n"}
+      expect "GET_LINE keyedit.prompt" {send "save\n"}
+      expect "GOT_IT"
+    }
+
+    wait
+    send_user "$CONFIG_FILE: \"$(echo -ne $1 | tr A-Z a-z)\" chosen successfully. [ expr \$uid_count - 1 ] UIDs deleted from public key \"$KEYID\".\n"
+    interact
+
+EOF
+}
+
+# main -
+# command line checking
+if [ -z "$2" -a "$1" != "-c" -a "$1" != "-h" -a "$1" != "-v" ]; then
+  usage
+  exit 1
+else
+  CONFIG_FILE="$2"
+  CONFIG_PATH="$FIRMA_LIST_PATH/$2"
+  CONFIG="$CONFIG_PATH/$2.conf"
+fi
+
+# if the configuration file exists, disable "sourcepath" and evaluate the parameters
+if [ "$1" != "-c" -a "$1" != "-h" -a "$1" != "-v" ]; then
+  if [ -f $CONFIG ]; then
+    shopt -u sourcepath && source $CONFIG
+  else
+    echo "$(basename $0): Configuration file \"$CONFIG\" could not be found."
+    exit 1
+  fi
+fi
+
+declare -a MESSAGE
+declare -a GPG_MESSAGE
+declare n
+export LANG=en_US
+
+# get gpg parameters and check the config
+if [ "$1" = "-a" -o "$1" = "-p" -o "$1" = "-r" ]; then
+  gpg_args
+  check_config
+fi
+
+# command line parsing
+if [ "$1" = "-a" ]; then
+
+  declare -a ADMINCOMMANDS
+
+  n=0
+  while read STDIN; do
+    ADMINCOMMANDS[$n]="$STDIN\n"
+    ((n++))
+  done
+
+  for i in $(seq 0 $((${#ADMINCOMMANDS[@]} - 1))); do
+    if [ ! -z "$(echo -ne ${ADMINCOMMANDS[$i]})" -a "$(echo -ne ${ADMINCOMMANDS[$i]} | cut -c1)" != "#" ]; then
+      list_admin $(echo -ne "${ADMINCOMMANDS[$i]}")
+    fi
+  done
+
+elif [ "$1" = "-c" ]; then
+  newlist
+elif [ "$1" = "-h" ]; then
+  usage
+elif [ "$1" = "-p" ]; then
+  process_message
+elif [ "$1" = "-r" ]; then
+  list_request
+elif [ "$1" = "-v" ]; then
+  version
+else
+  usage
+  exit 1
+fi 
+