├── wman ├── letter ├── memo ├── lprr ├── repeat ├── todo ├── 2up ├── s3sh ├── doc2pdf ├── note ├── abc2pdf ├── agenda.el ├── backup-cloudlib ├── typeOf ├── abc2mp3 ├── tunnel ├── daily-mail ├── find_duplicate_words ├── zotero-upload.py ├── README ├── gdc ├── editlabel ├── word2pdf ├── backup ├── skype.py ├── mutt_bgrun ├── view_attachment ├── texdiff.pl ├── calnet └── googlecode_upload.py /wman: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgm/scripts/HEAD/wman -------------------------------------------------------------------------------- /letter: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | pandoc --template letter -o ${1%.*}.pdf $@ 3 | -------------------------------------------------------------------------------- /memo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | pandoc --template memo -o ${1%.*}.pdf "$@" 3 | -------------------------------------------------------------------------------- /lprr: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # print on Ricoh printer 3 | lpr -PRicohCopier -o sides=two-sided-long-edge "$@" 4 | -------------------------------------------------------------------------------- /repeat: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # repeat n "command here" 3 | # repeats the command n times 4 | for i in $(seq 1 $1); do $2; done 5 | 6 | -------------------------------------------------------------------------------- /todo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CLIENT=${EMACSCLIENT-"emacsclient"} 4 | 5 | $CLIENT --alternate-editor='' '~/Dropbox/org/todo.org' 6 | -------------------------------------------------------------------------------- /2up: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | pdfjam "$1" --trim '1cm 0.4cm 1cm 0.4cm' --clip true --outfile /dev/stdout | \ 3 | pdfnup --outfile "${1%.pdf}-2up.pdf" 4 | -------------------------------------------------------------------------------- /s3sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | AMAZON_ACCESS_KEY_ID=$(cat $HOME/Private/aws-access-key-id) \ 3 | AMAZON_SECRET_ACCESS_KEY=$(cat $HOME/Private/aws-secret-access-key) \ 4 | /var/lib/gems/1.8/bin/s3sh 5 | -------------------------------------------------------------------------------- /doc2pdf: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Uses OpenOffice to convert a Word doc to PDF 3 | 4 | DIR=`pwd` 5 | DOC="$DIR/$1" 6 | 7 | /usr/bin/libreoffice -invisible "macro:///Standard.Module1.ConvertWordToPDF($DOC)" 8 | 9 | -------------------------------------------------------------------------------- /note: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | NOTEFILE=$HOME/Wiki/UnfiledNotes 3 | case $1 in 4 | -e) 5 | vim -X $NOTEFILE 6 | ;; 7 | -l) 8 | cat $NOTEFILE 9 | ;; 10 | *) 11 | echo >> $NOTEFILE 12 | date >> $NOTEFILE 13 | cat >> $NOTEFILE 14 | ;; 15 | esac 16 | -------------------------------------------------------------------------------- /abc2pdf: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Convert a text file with abc musical notation (abcnotation.com) 3 | # to a PDF, using abc2ps. 4 | PID=$$ 5 | TMPPS="/tmp/${1%.abc}-$PID.ps" 6 | PDF="${1%.abc}.pdf" 7 | abc2ps "$@" -maxs 2000 -O $TMPPS 8 | ps2pdf $TMPPS $PDF 9 | echo "Created $PDF" 10 | rm $TMPPS 11 | -------------------------------------------------------------------------------- /agenda.el: -------------------------------------------------------------------------------- 1 | ;; Invoke with: 2 | ;; emacs -batch -l /path/to/agenda.el 2>/dev/null 3 | 4 | (require 'org-install) 5 | (add-to-list 'auto-mode-alist '("\\.org$" . org-mode)) 6 | (org-batch-agenda "a" 7 | org-agenda-include-diary nil 8 | org-agenda-files (quote ("~/org/todo.org"))) 9 | 10 | -------------------------------------------------------------------------------- /backup-cloudlib: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export AWS_ACCESS_KEY_ID=`cat ~/Private/aws-access-key-id` 3 | export AWS_SECRET_ACCESS_KEY=`cat ~/Private/aws-secret-access-key` 4 | export CLOUDLIB_LIBRARY_NAME=john-macfarlane-library 5 | export GEM_HOME=$HOME/.gems 6 | $GEM_HOME/bin/cloudlib dump $HOME/cloudlib-backup 7 | -------------------------------------------------------------------------------- /typeOf: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # script finds the type of a Haskell expression 3 | # argument is file containing the expression 4 | # the expression itself goes to stdin 5 | 6 | FILE=$* 7 | DECL=`cat` 8 | ID=`echo $DECL | sed 's/^\([^ ]*\).*/\1/'` 9 | echo ":t $ID" | ghci -v0 -cpp -fglasgow-exts -w $FILE 10 | echo $DECL 11 | -------------------------------------------------------------------------------- /abc2mp3: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Convert a text file with abc music notation (abcnotation.com) 3 | # to MP3, suing abc2ps and lame. 4 | PID=$$ 5 | TITLE=$(abc2ps -L "$1" | sed -n '2s/\s*\S*\s*\S*\s*\S*\s*\(.*\)/\1/p') 6 | WAV=Abc.wav 7 | MP3="${1%.abc}.mp3" 8 | abc2ps -a -Q ${BPM:=120} -W -A "$@" 9 | lame --tt "${TITLE}" $WAV $MP3 10 | echo "Created $MP3 for $TITLE" 11 | rm $WAV 12 | -------------------------------------------------------------------------------- /tunnel: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #script to establish ssh tunnel connection to protagoras 3 | 4 | if [ $# -eq 0 ]; then 5 | echo "Usage: tunnel username@machine.dest" 6 | exit 1 7 | fi 8 | 9 | DEST=$1 10 | 11 | echo "Port on $DEST to connect to: " 12 | read destport 13 | echo "Port on localhost to tunnel through: " 14 | read localport 15 | echo "Establishing tunnel from local port $localport to port $destport on $DEST." 16 | ssh -N -L $localport:localhost:$destport $DEST 17 | 18 | -------------------------------------------------------------------------------- /daily-mail: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # mails todo list and unfiled notes to me, unless empty 3 | 4 | tempfile=`mktemp /tmp/mailXXXXXXXX` 5 | todofile="$HOME/org/todo.org" 6 | 7 | addline () { echo $1 >> $tempfile ; } 8 | addfile () { cat $1 >> $tempfile ; } 9 | 10 | addline "To: John MacFarlane " 11 | addline "Subject: Todo list" 12 | addline "" 13 | addline "Good morning John!" 14 | addline "" 15 | 16 | addline "Here are some things to work on today:" 17 | addline "" 18 | sed -ne '/TODO/p' $todofile >> $tempfile 19 | 20 | cat $tempfile | /usr/sbin/sendmail -F "Your Computer" -f "jgm" -i jgm@berkeley.edu 21 | rm $tempfile 22 | 23 | -------------------------------------------------------------------------------- /find_duplicate_words: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | # Finds duplicate adjacent words. 4 | 5 | use strict ; 6 | 7 | my $DupCount = 0 ; 8 | 9 | if (!@ARGV) { 10 | print "usage: dups ...\n" ; 11 | exit ; 12 | } 13 | 14 | while (1) { 15 | my $FileName = shift @ARGV ; 16 | 17 | # Exit code = number of duplicates found. 18 | exit $DupCount if (!$FileName) ; 19 | 20 | open FILE, $FileName or die $!; 21 | 22 | my $LastWord = "" ; 23 | my $LineNum = 0 ; 24 | 25 | while () { 26 | chomp ; 27 | 28 | $LineNum ++ ; 29 | 30 | my @words = split (/(\W+)/) ; 31 | 32 | foreach my $word (@words) { 33 | # Skip spaces: 34 | next if $word =~ /^\s*$/ ; 35 | 36 | # Skip punctuation: 37 | if ($word =~ /^\W+$/) { 38 | $LastWord = "" ; 39 | next ; 40 | } 41 | 42 | # Found a dup? 43 | if ($word eq $LastWord) { 44 | print "$FileName:$LineNum $word\n" ; 45 | $DupCount ++ ; 46 | } 47 | 48 | # Mark this as the last word: 49 | $LastWord = $word ; 50 | } 51 | } 52 | 53 | close FILE ; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /zotero-upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Uploads contents of stdin with name derived from first argument 4 | # Assumes ZOTERO_KEY and ZOTERO_USER are set 5 | 6 | from pyzotero import zotero 7 | # import json 8 | import sys 9 | import os 10 | import os.path 11 | import tempfile 12 | 13 | if len(sys.argv) < 2: 14 | sys.stderr.write("Give filename as first argument") 15 | sys.exit(1) 16 | else: 17 | nicename = sys.argv[1] 18 | 19 | try: 20 | key = os.environ['ZOTERO_KEY'] 21 | except KeyError: 22 | sys.stderr.write("ZOTERO_KEY environment variable must be set\n") 23 | sys.exit(1) 24 | 25 | try: 26 | user = os.environ['ZOTERO_USER'] 27 | except KeyError: 28 | sys.stderr.write("ZOTERO_USER environment variable must be set\n") 29 | sys.exit(1) 30 | 31 | zot = zotero.Zotero(user, 'user', key, True) 32 | 33 | # def prettyprint(x): 34 | # print(json.dumps(x, sort_keys=False, indent=2, separators=(',', ': '))) 35 | 36 | try: 37 | tmpdir = tempfile.mkdtemp() 38 | tmpfile = tmpdir + "/" + nicename 39 | f = open(tmpfile, 'w') 40 | f.write(sys.stdin.read()) 41 | sys.stdin.flush() 42 | f.flush() 43 | f.close 44 | zot.attachment_simple([tmpfile]) 45 | finally: 46 | os.remove(tmpfile) 47 | 48 | sys.exit(0) 49 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | A collection of small scripts that serve various purposes. 2 | 3 | abc2mp3 4 | convert abc musical notation to mp3 (wraps abc2ps, lame) 5 | 6 | abc2pdf 7 | convert abc musical notation to PDF (wraps abc2ps) 8 | 9 | backup 10 | remote backup script, wrapping duplicity 11 | 12 | backup-cloudlib 13 | backup cloudlib locally 14 | 15 | calnet 16 | lookup names in Calnet LDAP directory 17 | 18 | daily-mail 19 | sends a daily email with todos and notes 20 | 21 | doc2pdf 22 | converts Word to PDF using OpenOffice 23 | 24 | find_duplicate_words 25 | find duplicate words in a text 26 | 27 | googlecode_upload.py 28 | upload to googlecode downloads 29 | 30 | letter 31 | wrapper around pandoc and latex to produce PDF letter from markdown 32 | 33 | note 34 | add a note to a list of unstructured notes 35 | 36 | repeat 37 | repeats a command a given number of times 38 | 39 | s3sh 40 | a wrapper around the s3sh gem 41 | 42 | skype.py 43 | interact with skype from command line 44 | 45 | texdiff.pl 46 | diff for TeX files 47 | 48 | todo 49 | starts vim with todo list 50 | 51 | tunnel 52 | wrapper for setting up an ssh tunnel 53 | 54 | typeOf 55 | uses ghci to determine type of Haskell expression 56 | 57 | wiki 58 | start vim with local wiki 59 | 60 | wman 61 | fetch man pages for different OSs 62 | 63 | word2pdf 64 | convert Word files to PDF from the command line, using OpenOffice 65 | 66 | 67 | -------------------------------------------------------------------------------- /gdc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # https://github.com/mmilidoni/github-downloads-count 3 | 4 | import sys 5 | 6 | if (len(sys.argv) < 2): 7 | print "Usage: " + sys.argv[0] + " github-user [github-project]" 8 | exit(1) 9 | 10 | try: 11 | import requests 12 | except ImportError: 13 | print "Error: requests is not installed" 14 | print "Installing Requests is simple with pip:\n pip install requests" 15 | print "More info: http://docs.python-requests.org/en/latest/" 16 | exit(1) 17 | import cStringIO 18 | import json 19 | 20 | 21 | def dict_to_object(d): 22 | if '__class__' in d: 23 | class_name = d.pop('__class__') 24 | module_name = d.pop('__module__') 25 | module = __import__(module_name) 26 | class_ = getattr(module, class_name) 27 | args = dict((key.encode('ascii'), value) for key, value in d.items()) 28 | inst = class_(**args) 29 | else: 30 | inst = d 31 | return inst 32 | 33 | 34 | def ensure_str(s): 35 | if isinstance(s, unicode): 36 | s = s.encode('utf-8') 37 | return s 38 | 39 | full_names = [] 40 | 41 | if len(sys.argv) == 3: 42 | full_names.append(sys.argv[1] + "/" + sys.argv[2]) 43 | else: 44 | buf = cStringIO.StringIO() 45 | r = requests.get('https://api.github.com/users/' + sys.argv[1] + "/repos") 46 | myobj = r.json() 47 | 48 | for rep in myobj: 49 | full_names.insert(0, ensure_str(rep['full_name'])) 50 | 51 | 52 | for full_name in full_names: 53 | buf = cStringIO.StringIO() 54 | r = requests.get('https://api.github.com/repos/' + full_name + '/releases') 55 | myobj = r.json() 56 | 57 | for p in myobj: 58 | if "assets" in p: 59 | for asset in p['assets']: 60 | print (asset['name'] + ": " + str(asset['download_count']) + 61 | " downloads") 62 | else: 63 | print "No data" 64 | -------------------------------------------------------------------------------- /editlabel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $1 is the action (append, show, remove) 4 | # $2 is the filename 5 | 6 | # Configuration 7 | LFILE="$HOME/.labels" 8 | 9 | 10 | ACTION="$1" 11 | FNAME="$2" 12 | NFNAME="/tmp/editlabels-`basename "$2"`.$$" 13 | 14 | function asklabel() { 15 | LNAME="" 16 | while [ "x$LNAME" == "x" ]; do 17 | LNAME=`rlwrap -S "Insert label: " -D2 -f $LFILE -H $LFILE -o cat` 18 | done 19 | } 20 | 21 | 22 | if [ "$ACTION" == "menu" ]; then 23 | function getact() { 24 | read -p "Append/Remove/Show/Clean/List: " ACT 25 | if [ "$ACT" == "a" ]; then 26 | ACTION=append 27 | elif [ "$ACT" == "r" ]; then 28 | ACTION=remove 29 | elif [ "$ACT" == "s" ]; then 30 | ACTION=show 31 | elif [ "$ACT" == "c" ]; then 32 | ACTION=clean 33 | elif [ "$ACT" == "l" ]; then 34 | ACTION=list 35 | else 36 | echo "Invalid action" 37 | getact 38 | fi 39 | } 40 | getact 41 | fi 42 | 43 | 44 | if [ "$ACTION" == "append" ]; then 45 | ACT=`formail -c -X X-Label < "$FNAME"` 46 | asklabel 47 | if [ "$ACT" == "" ]; then 48 | NEW="X-Label: $LNAME" 49 | else 50 | NEW="$ACT, $LNAME" 51 | fi 52 | 53 | formail -I "$NEW" < "$FNAME" > "$NFNAME" 54 | 55 | elif [ "$ACTION" == "remove" ]; then 56 | ACT=`formail -c -X X-Label < "$FNAME"` 57 | asklabel 58 | NEW=`echo $ACT | sed "s/, $LNAME//g" | sed "s/$LNAME, //g" | sed "s/: $LNAME/:/g"` 59 | formail -I "$NEW" < "$FNAME" > "$NFNAME" 60 | 61 | elif [ "$ACTION" == "show" ]; then 62 | formail -c -X "X-Label:" < "$FNAME" 63 | read -p "Press any key to continue" 64 | 65 | elif [ "$ACTION" == "clean" ]; then 66 | formail -I "X-Label:" < "$FNAME" > "$NFNAME" 67 | 68 | elif [ "$ACTION" == "list" ]; then 69 | echo "Available labels (from ~/.labels):" 70 | cat $LFILE 71 | read -p "Press any key to continue" 72 | fi 73 | 74 | 75 | # if we created a new file, step over the old one 76 | if [ -f "$NFNAME" ]; then 77 | mv "$NFNAME" "$FNAME" 78 | fi 79 | -------------------------------------------------------------------------------- /word2pdf: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Modified slightly from 4 | # http://www.togaware.com/linux/survivor/Convert_MS_Word.html 5 | 6 | # This script uses openoffice to convert word documents to PDF 7 | # It assumes that you've added some macros to your openoffice instance. 8 | # to do this, start up oowriter, go Tools => Macros => Organize Macros => 9 | # OpenOffice.org Basic. Then go to My Macros -> Standard -> Module1, and 10 | # edit to include this code: 11 | # 12 | # REM ***** BASIC ***** 13 | # 14 | # Sub ConvertWordToPDF(cFile) 15 | # cURL = ConvertToURL(cFile) 16 | # 17 | # ' Open the document. 18 | # ' Just blindly assume that the document is of a type that OOo will 19 | # ' correctly recognize and open -- without specifying an import filter. 20 | # oDoc = StarDesktop.loadComponentFromURL(cURL, "_blank", 0, Array(MakePropertyValue("Hidden", True), )) 21 | # 22 | # Dim comps 23 | # comps = split (cFile, ".") 24 | # If UBound(comps) > 0 Then 25 | # comps(UBound(comps)) = "pdf" 26 | # cfile = join (comps, ".") 27 | # Else 28 | # cfile = cFile + ".pdf" 29 | # Endif 30 | # 31 | # cURL = ConvertToURL(cFile) 32 | # 33 | # ' Save the document using a filter. 34 | # oDoc.storeToURL(cURL, Array(MakePropertyValue("FilterName", "writer_pdf_Export"), )) 35 | # 36 | # oDoc.close(True) 37 | # 38 | # End Sub 39 | # 40 | # Function MakePropertyValue( Optional cName As String, Optional uValue ) As com.sun.star.beans.PropertyValue 41 | # Dim oPropertyValue As New com.sun.star.beans.PropertyValue 42 | # If Not IsMissing( cName ) Then 43 | # oPropertyValue.Name = cName 44 | # EndIf 45 | # If Not IsMissing( uValue ) Then 46 | # oPropertyValue.Value = uValue 47 | # EndIf 48 | # MakePropertyValue() = oPropertyValue 49 | # End Function 50 | 51 | if [ $# -eq 0 ]; then 52 | echo "Usage: word2pdf [word file]..." 53 | exit 1 54 | fi 55 | 56 | DIR=$(pwd) 57 | 58 | DOC=$DIR/$1 59 | for doc in "$@"; do 60 | /usr/lib/openoffice/program/soffice.bin -writer -invisible "macro:///Standard.Module1.ConvertWordToPDF($DIR/$doc)" && echo "Created $DIR/${doc%.*}.pdf" 61 | done 62 | -------------------------------------------------------------------------------- /backup: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Use duplicity to backup to s3 3 | 4 | export AWS_ACCESS_KEY_ID=$(cat $HOME/Private/aws-access-key-id) 5 | export AWS_SECRET_ACCESS_KEY=$(cat $HOME/Private/aws-secret-access-key) 6 | export PASSPHRASE=$(cat $HOME/Private/gpg-passphrase) 7 | 8 | DUPLICITY=/usr/bin/duplicity 9 | BUCKET=john-macfarlane-protagoras 10 | BUCKET_PATH=backups/home/jgm 11 | URL=s3+http://$BUCKET/${BUCKET_PATH} 12 | GPG_KEY=D507B947 # E24A2ECB 13 | PRUNE_TIME=30D 14 | FULL_TIME=30D 15 | VOLUME_SIZE=50 16 | EXCLUDES=$HOME/.backup-excludes 17 | SOURCEDIR=$HOME 18 | type= 19 | status=0 20 | type= 21 | 22 | if [ $# -ge 1 ]; then 23 | type=$1 24 | shift 25 | fi 26 | 27 | usage() { 28 | PROG=${0##*/} 29 | echo >&2 "$PROG: Backs up $SOURCEDIR to $URL." 30 | echo >&2 "Usage:" 31 | echo >&2 " $PROG [opts] incremental backup if possible, otherwise full" 32 | echo >&2 " $PROG list-files [opts] list backed up files" 33 | echo >&2 " $PROG status [opts] list all backup sets" 34 | echo >&2 " $PROG cleanup [opts] cleanup after a failed backup" 35 | echo >&2 " $PROG restore [PATH1] [--file-to-restore PATH2] [-t TIME] [opts]" 36 | echo >&2 " restore PATH2 (or $SOURCEDIR) as of TIME to PATH1 (or $SOURCEDIR)" 37 | echo >&2 "Options: [opts] may include any duplicity options, for example:" 38 | echo >&2 " -v5 verbose output" 39 | echo >&2 " --volsize NUM set volume size in Mb" 40 | echo >&2 "See duplicity(1) man page for details." 41 | exit 0 42 | } 43 | 44 | case "$type" in 45 | restore) $DUPLICITY restore \ 46 | --encrypt-key ${GPG_KEY} \ 47 | "$URL" "$@" 48 | break ;; 49 | list-files) dir=$2 50 | $DUPLICITY list-current-files \ 51 | --encrypt-key ${GPG_KEY} \ 52 | "$URL/$dir" "$@" 53 | break ;; 54 | incr) 55 | $DUPLICITY \ 56 | --exclude-globbing-filelist $EXCLUDES \ 57 | --encrypt-key ${GPG_KEY} \ 58 | --volsize ${VOLUME_SIZE} \ 59 | --full-if-older-than ${FULL_TIME} \ 60 | $SOURCEDIR $URL "$@" && \ 61 | $DUPLICITY remove-older-than ${PRUNE_TIME} --force $URL 62 | break ;; 63 | status) $DUPLICITY collection-status $URL "$@" 64 | break;; 65 | cleanup) $DUPLICITY cleanup $URL "$@" 66 | break;; 67 | -h|--help) usage 68 | break;; 69 | *) echo >&2 "Unknown command: $type" 70 | status=1 71 | break ;; 72 | esac 73 | 74 | export AWS_ACCESS_KEY_ID= 75 | export AWS_SECRET_ACCESS_KEY= 76 | export PASSPHRASE= 77 | 78 | exit $status 79 | -------------------------------------------------------------------------------- /skype.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Interact with skype from the command line, using skype API 4 | # 5 | # skype toggle 6 | # skype hide 7 | # skype answer 8 | # skype hangup 9 | # skip call [number] 10 | 11 | import sys 12 | import traceback 13 | import re 14 | 15 | import dbus 16 | import dbus.service 17 | #for event loop 18 | import gobject 19 | from dbus.mainloop.glib import DBusGMainLoop 20 | 21 | ####################################################### 22 | #catching the events 23 | class Callback_obj(dbus.service.Object): 24 | def __init__(self, bus, object_path): 25 | dbus.service.Object.__init__(self, bus, object_path, bus_name='com.Skype.API') 26 | 27 | @dbus.service.method(dbus_interface='com.Skype.API') 28 | def Notify(self, message_text): 29 | pass 30 | 31 | ###################################################### 32 | 33 | args = sys.argv 34 | 35 | if len(sys.argv) > 1: 36 | command = sys.argv[1].lower() 37 | else: 38 | command = "toggle" 39 | 40 | arguments = sys.argv[2:] 41 | 42 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 43 | 44 | #connect to the session 45 | session_bus = dbus.SessionBus() 46 | 47 | #connect to Skype 48 | skype = session_bus.get_object('com.Skype.API', '/com/Skype') 49 | 50 | #ok lets hit up skype now! 51 | answer = skype.Invoke('NAME PythonManageCall') 52 | if answer != 'OK': 53 | sys.exit('Could not bind to Skype client') 54 | answer = skype.Invoke('PROTOCOL 5') 55 | if (answer != 'PROTOCOL 5'): 56 | sys.exit('Could not agree on protocol!') 57 | 58 | #tie up the events to the skype 59 | skype_callback = Callback_obj(session_bus, '/com/Skype/Client') 60 | 61 | if command == "toggle": 62 | state = skype.Invoke('GET WINDOWSTATE') 63 | if state == 'WINDOWSTATE HIDDEN': 64 | skype.Invoke('SET WINDOWSTATE NORMAL') 65 | else: 66 | skype.Invoke('SET WINDOWSTATE HIDDEN') 67 | elif command == "hide": 68 | skype.Invoke('SET WINDOWSTATE HIDDEN') 69 | elif command == "answer": 70 | answer = skype.Invoke('SEARCH ACTIVECALLS') #get calls going on right now! 71 | if(re.search(r'CALLS [0-9]+', answer)): # see if there was a call 72 | callNum = re.search(r'CALLS ([0-9]+)', answer).group(1) 73 | print 'Answering Call ', callNum 74 | skype.Invoke('SET CALL ' + callNum + ' STATUS INPROGRESS') 75 | elif command == "hangup": 76 | answer = skype.Invoke('SEARCH ACTIVECALLS') #get calls going on right now! 77 | if(re.search(r'CALLS [0-9]+', answer)): # see if there was a call 78 | callNum = re.search(r'CALLS ([0-9]+)', answer).group(1) 79 | print 'Answering Call ', callNum 80 | skype.Invoke('SET CALL ' + callNum + ' STATUS FINISHED') 81 | elif command == "call": 82 | if len(arguments) < 1: 83 | print 'You need to specify a number to call.' 84 | exit 85 | else: 86 | skype.Invoke('CALL ' + ', '.join(arguments)) 87 | else: 88 | print "Unknown command: ", command 89 | 90 | -------------------------------------------------------------------------------- /mutt_bgrun: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # @(#) mutt_bgrun $Revision: 1.4 $ 3 | 4 | # mutt_bgrun - run an attachment viewer from mutt in the background 5 | # Copyright (C) 1999-2002 Gary A. Johnson 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 | 21 | # SYNOPSIS 22 | # mutt_bgrun viewer [viewer options] file 23 | # 24 | # DESCRIPTION 25 | # Mutt invokes external attachment viewers by writing the 26 | # attachment to a temporary file, executing the pipeline specified 27 | # for that attachment type in the mailcap file, waiting for the 28 | # pipeline to terminate, writing nulls over the temporary file, 29 | # then deleting it. This causes problems when using graphical 30 | # viewers such as qvpview and acroread to view attachments. 31 | # 32 | # If qvpview, for example, is executed in the foreground, the mutt 33 | # user interface is hung until qvpview exits, so the user can't do 34 | # anything else with mutt until he or she finishes reading the 35 | # attachment and exits qvpview. This is especially annoying when 36 | # a message contains several MS Office attachments--one would like 37 | # to have them all open at once. 38 | # 39 | # If qvpview is executed in the background, it must be given 40 | # enough time to completely read the file before returning control 41 | # to mutt, since mutt will then obliterate the file. Qvpview is 42 | # so slow that this time can exceed 20 seconds, and the bound is 43 | # unknown. So this is again annoying. 44 | # 45 | # The solution provided here is to invoke the specified viewer 46 | # from this script after first copying mutt's temporary file to 47 | # another temporary file. This script can then quickly return 48 | # control to mutt while the viewer can take as much time as it 49 | # needs to read and render the attachment. 50 | # 51 | # EXAMPLE 52 | # To use qvpview to view MS Office attachments from mutt, add the 53 | # following lines to mutt's mailcap file. 54 | # 55 | # application/msword; mutt_bgrun qvpview %s 56 | # application/vnd.ms-excel; mutt_bgrun qvpview %s 57 | # application/vnd.ms-powerpoint; mutt_bgrun qvpview %s 58 | # 59 | # AUTHOR 60 | # Gary A. Johnson 61 | # 62 | # 63 | # ACKNOWLEDGEMENTS 64 | # My thanks to the people who have commented on this script and 65 | # offered solutions to shortcomings and bugs, especially Edmund 66 | # GRIMLEY EVANS and Andreas Somogyi 67 | # . 68 | 69 | prog=${0##*/} 70 | 71 | # Check the arguments first. 72 | 73 | if [ "$#" -lt "2" ] 74 | then 75 | echo "usage: $prog viewer [viewer options] file" >&2 76 | exit 1 77 | fi 78 | 79 | # Separate the arguments. Assume the first is the viewer, the last is 80 | # the file, and all in between are options to the viewer. 81 | 82 | viewer="$1" 83 | shift 84 | 85 | while [ "$#" -gt "1" ] 86 | do 87 | options="$options $1" 88 | shift 89 | done 90 | 91 | file=$1 92 | 93 | # Create a temporary directory for our copy of the temporary file. 94 | # 95 | # This is more secure than creating a temporary file in an existing 96 | # directory. 97 | 98 | tmpdir=/tmp/$LOGNAME$$ 99 | umask 077 100 | mkdir "$tmpdir" || exit 1 101 | tmpfile="$tmpdir/${file##*/}" 102 | 103 | # Copy mutt's temporary file to our temporary directory so that we can 104 | # let mutt overwrite and delete it when we exit. 105 | 106 | cp "$file" "$tmpfile" 107 | 108 | # Run the viewer in the background and delete the temporary files when done. 109 | 110 | ( 111 | "$viewer" $options "$tmpfile" 112 | rm -f "$tmpfile" 113 | rmdir "$tmpdir" 114 | ) & 115 | -------------------------------------------------------------------------------- /view_attachment: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Author: Eric Gebhart 4 | # 5 | # Purpose: To be called by mutt as indicated by .mailcap to handle mail attachments. 6 | # 7 | # Function: Copy the given file to a temporary directory so mutt 8 | # Won't delete it before it is read by the application. 9 | # 10 | # Along the way, discern the file type or use the type 11 | # That is given. 12 | # 13 | # Finally use 'open' or 'open -a' if the third argument is 14 | # given. 15 | # 16 | # 17 | # Arguments: 18 | # 19 | # $1 is the file 20 | # $2 is the type - for those times when file magic isn't enough. 21 | # I frequently get html mail that has no extension 22 | # and file can't figure out what it is. 23 | # 24 | # Set to '-' if you don't want the type to be discerned. 25 | # Many applications can sniff out the type on their own. 26 | # And they do a better job of it too. 27 | # 28 | # Open Office and MS Office for example. 29 | # 30 | # $3 is open with. as in open -a 'open with this .app' foo.xls 31 | # 32 | # Examples: These are typical .mailcap entries which use this program. 33 | # 34 | # Image/JPEG; /usr/local/bin/view_attachment %s 35 | # Image/PNG; /usr/local/bin/view_attachment %s 36 | # Image/GIF; /usr/local/bin/view_attachment %s 37 | # 38 | # Application/PDF; /usr/local/bin/view_attachment %s 39 | # 40 | # #This HTML example passes the type because file doesn't always work and 41 | # #there aren't always extensions. 42 | # 43 | # text/html; /usr/local/bin/view_attachment %s html 44 | # 45 | # # If your Start OpenOffice.org.app is spelled with a space like this one, <-- 46 | # # then you'll need to precede the space with a \ . I found that too painful 47 | # # and renamed it with an _. 48 | # 49 | # Application/vnd.ms-excel; /usr/local/bin/view_attachment %s "-" '/Applications/OpenOffice.org1.1.2/Start_OpenOffice.org.app' 50 | # Application/msword; /usr/local/bin/view_attachment %s "-" '/Applications/OpenOffice.org1.1.2/Start_OpenOffice.org.app' 51 | # 52 | # 53 | # Debugging: If you have problems set debug to 'yes'. That will cause a debug file 54 | # be written to /tmp/mutt_attach/debug so you can see what is going on. 55 | # 56 | # See Also: The man pages for open, file, basename 57 | # 58 | 59 | # the tmp directory to use. 60 | tmpdir="/tmp/mutt_attach" 61 | 62 | # the name of the debug file if debugging is turned on. 63 | debug_file=$tmpdir/debug 64 | 65 | # debug. yes or no. 66 | debug="no" 67 | #debug="yes" 68 | 69 | type=$2 70 | open_with=$3 71 | 72 | # make sure the tmpdir exists. 73 | mkdir -p $tmpdir 74 | 75 | # clean it out. Remove this if you want the directory 76 | # to accumulate attachment files. 77 | rm -f $tmpdir/* 78 | 79 | # Mutt puts everything in /tmp by default. 80 | # This gets the basic filename from the full pathname. 81 | filename=`basename $1` 82 | 83 | # get rid of the extenson and save the name for later. 84 | file=`echo $filename | cut -d"." -f1` 85 | 86 | if [ $debug = "yes" ]; then 87 | echo "1:" $1 " 2:" $2 " 3:" $3 > $debug_file 88 | echo "Filename:"$filename >> $debug_file 89 | echo "File:"$file >> $debug_file 90 | echo "===========================" >> $debug_file 91 | fi 92 | 93 | # if the type is empty then try to figure it out. 94 | if [ -z $type ]; then 95 | type=`file -bi $1 | cut -d"/" -f2` 96 | fi 97 | 98 | # if the type is '-' then we don't want to mess with type. 99 | # Otherwise we are rebuilding the name. Either from the 100 | # type that was passed in or from the type we discerned. 101 | if [ $type = "-" ]; then 102 | newfile=$filename 103 | else 104 | newfile=$file.$type 105 | fi 106 | 107 | newfile=$tmpdir/$newfile 108 | 109 | # Copy the file to our new spot so mutt can't delete it 110 | # before the app has a chance to view it. 111 | cp $1 $newfile 112 | 113 | if [ $debug = "yes" ]; then 114 | echo "File:" $file "TYPE:" $type >> $debug_file 115 | echo "Newfile:" $newfile >> $debug_file 116 | echo "Open With:" $open_with >> $debug_file 117 | fi 118 | 119 | # If there's no 'open with' then we can let preview do it's thing. 120 | # Otherwise we've been told what to use. So do an open -a. 121 | 122 | if [ -z $open_with ]; then 123 | open $newfile 124 | else 125 | open -a "$open_with" $newfile 126 | fi 127 | -------------------------------------------------------------------------------- /texdiff.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # This is a perl implementation of TeXdiff, derived from the original bash 4 | # script created by Robert Maron (robmar@mimuw.edu.pl), available at 5 | # http://www.robmar.net/TexDiff/ 6 | # 7 | # it requires the wdiff tools to operate properly. You may obtain a copy at 8 | # http://www.robmar.net/TexDiff/wdiff-0.5g.tar.gz 9 | # or 10 | # http://www.gnu.org/directory/Text_creation_and_manipulation/Word_processing/wdiff.html 11 | # 12 | # For installation, follow the "Usage" directions given on the TexDiff 13 | # Homepage (reprinted/modified here for convenience): 14 | # 15 | # * Unpack wdiff sources, then patch it with: 16 | # patch -d wdiff-0.5g -p1 < patch-wdiff 17 | # * Compile: 18 | # cd wdiff-0.5g ; ./configure && make && make install 19 | # * Copy the script texdiff.pl to /usr/local/bin/ 20 | # * To create sample-diff.tex from sample-old.tex and sample.tex, run: 21 | # texdiff sample-old.tex sample.tex sample-diff.tex 22 | # * generate the PDF or PS file using one of the following: 23 | # dvipdfm sample.tex 24 | # or 25 | # dvips sample.tex 26 | # 27 | # $ Version: 0.1; Date: 7/16/02 $ 28 | 29 | use strict; 30 | 31 | my ($in1,$in2,$out) = @ARGV; 32 | 33 | print "tex-word-diff( $in1, $in2 ) > $out\n"; 34 | 35 | write_temp($in1,'tmp1.'.$$); 36 | write_temp($in2,'tmp2.'.$$); 37 | 38 | my $buf = "%%% preamble included from $in2:\n"; 39 | $buf .= read_preamble($in2); 40 | 41 | # print `bash /home/temp/TexDiff/texdiff tmp1 tmp2 tmp3`; 42 | my $cmd_opts = ("--avoid-wraps ". 43 | "--start-delete=\'\\TLSdel{\' --end-delete=\'}\' ". 44 | "--start-insert=\'\\TLSins{\' --end-insert=\'}\' ". 45 | "tmp1.$$ tmp2.$$"); 46 | $buf .= `/usr/bin/wdiff $cmd_opts`; 47 | # $buf .= system('wdiff',split(/\s/,$cmd_opts)); 48 | 49 | # add in the texdiff stuff (included at the end of this script) to the preamble 50 | my $addon; 51 | {local ($/); undef $/; $addon .= ;} 52 | $buf =~ s/(\\begin\{document\})/$addon$1/; 53 | 54 | # make sure that the author-thanks argument is contiguous. 55 | my $tmp = $1 if $buf =~ m/(\\thanks\{.*?\})/s; 56 | $tmp =~ s/\n\s+/\n/sg; 57 | $buf =~ s/\\thanks\{.*?\}/$tmp/s; 58 | 59 | # ifthenelse fails with TLSins 60 | $buf =~ s/\\TLS(ins|del)\{(\\ifthenelse[\{\}\\\w]+)\}/$2/sg; 61 | 62 | # ... as do figures and tables 63 | $buf =~ s/\\TLSdel\{(\\begin\{(figure|table).*)\}//g; 64 | $buf =~ s/\\TLSins\{(\\begin\{(figure|table).*)\}/$1/g; 65 | 66 | # ... and the bibliography, graphics, (and most other commands) 67 | foreach my $term ( qw( biblio includegraphics setboolean cite ) ) { 68 | $buf =~ s/\\TLSdel\{(\{?\\$term.*?)\}?\}\n?//g; 69 | $buf =~ s/\\TLSins\{(\{?\\$term.*?)\}?\}/$1/g; 70 | } 71 | # comment out any ins/del commands that have comments... 72 | $buf =~ s/(\\TLS(ins|del)\{.*?\%.*?\})/% $1/g; 73 | 74 | # swap all new-line commands out of the highlight 75 | # $buf =~ s!\\TLS(ins|del)\{(.*?)\\\\(.*?)\}!\\TLS$1\{$2$3\} \\\\!sg; 76 | 77 | # foreach my $k (sort keys %h) { 78 | # my %l = %{$h{$k}}; 79 | # print "***\n".$l{'old'}."***\n"; 80 | # print "+++\n".$l{'new'}."+++\n"; 81 | # } 82 | 83 | # remove any blank lines that are marked as del or ins 84 | $buf =~ s/\\TLS(ins|del)\{\s*\}//g; 85 | 86 | ### merge multi-line inserts and deletes: 87 | my @a=(0..9,'a'..'z','A'..'Z'); 88 | my $newline = map { $a[int rand @a] } (0..16); 89 | while ( $buf =~ s/(\n\\TLSins\{)([^\%\n]*)\}\n\\TLSins\{([^\%])/$1$2$newline $3/sg ) {} 90 | while ( $buf =~ s/(\n\\TLSdel\{)([^\%\n]*)\}\n\\TLSdel\{([^\%])/$1$2$newline $3/sg ) {} 91 | $buf =~ s/$newline/\n/g; 92 | 93 | if ( open(O,">$out") ) { 94 | print O $buf; close(O); 95 | } else { 96 | print STDOUT $buf; 97 | } 98 | 99 | unlink('tmp1.'.$$); 100 | unlink('tmp2.'.$$); 101 | 102 | sub read_preamble { 103 | my ($file,$out) = @_; 104 | 105 | open(I,"<$file") or return("can't open $file: $!\n"); 106 | my $flag = 1; 107 | my $str; 108 | while () { 109 | $flag = 0 if (m/begin\{document\}/); 110 | $str .= $_ if $flag; 111 | } 112 | close I; 113 | 114 | # the 'doublespace' package doesn't work with the 'color' package, so 115 | # swap it out with a work-around: 116 | my $wa = join("\n",' ', 117 | '%% texdiff comment:', 118 | '%% swapped \'doublespace\' package out with workaround:', 119 | '\newcommand{\singlespace}{\linespread{1.0}}', 120 | '\newcommand{\doublespace}{\linespread{2.0}}', 121 | '\linespread{2.0}', 122 | '%% end workaround' 123 | ); 124 | $str =~ s/\\usepackage\{doublespace}/$wa/; 125 | return $str; 126 | } 127 | 128 | sub write_temp { 129 | my ($file,$tmp) = @_; 130 | 131 | open(O,">$tmp") or return("can't open $tmp: $!\n"); 132 | open(I,"<$file") or return("can't open $file: $!\n"); 133 | my $flag = 0; 134 | my $picky_env; 135 | while () { 136 | $flag = 1 if (m/begin\{document\}/); 137 | # $picky_env = $1 if (m/begin\{(equation|displaymath|eqnarray|figure)/); 138 | # undef($picky_env) if (m/end\{$picky_env/); 139 | # $_ =~ s/\%.*$//e ; 140 | # next if ( ($picky_env) and ( m/^\s+$/) ) ; 141 | print O if ($flag); 142 | $flag = 0 if (m/end\{document\}/); 143 | } 144 | close I; 145 | close O; 146 | } 147 | 148 | 149 | # 150 | # (c) Copyright 2002 by W. Scott Hoge (shoge@ieee.org). 151 | # 152 | # This program is free software; you can redistribute it and/or modify 153 | # it under the terms of the GNU General Public License as published by 154 | # the Free Software Foundation; either version 2, or (at your option) 155 | # any later version. 156 | # 157 | # This program is distributed in the hope that it will be useful, 158 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 159 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 160 | # GNU General Public License for more details. 161 | # 162 | # You should have received a copy of the GNU General Public License 163 | # along with this program; if not, write to the Free Software Foundation, 164 | # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 165 | # You may also obtain a copy at http://www.gnu.org/copyleft/gpl.html 166 | # 167 | # Help support Free Software. The code is shared in the hopes of 168 | # making the computing world a little better. If you find it useful, 169 | # consider giving a donation (in code, time, or money) to the Free 170 | # Software or Open Source project of your choice. 171 | 172 | __DATA__ 173 | %%%% begin: texdiff preamble additions to show changes in compiled latex docs 174 | 175 | \RequirePackage[normalem]{ulem} 176 | \RequirePackage{color} 177 | 178 | \newcommand\TLSins[1]{ 179 | \textcolor{blue}{\uline{#1}}% 180 | } 181 | 182 | \newcommand\TLSdel[1]{ 183 | \textcolor{red}{\sout{#1}}% 184 | } 185 | 186 | %%%% end: texdiff preamble additions 187 | -------------------------------------------------------------------------------- /calnet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # usage: calnet NAME 3 | # searches for (last) NAME in calnet directory 4 | # 5 | # 6 | # Search the CalNet Directory Service using a 'uid' attribute 7 | # and return selected attributes of the UC Berkeley-affiliated 8 | # person, if any, that matches that 'uid' 9 | # 10 | # Prerequisite: Graham Barr's Perl-LDAP, whose home page is located at: 11 | # 12 | # http://perl-ldap.sourceforge.net/ 13 | # 14 | # For additional Perl-LDAP documentation and usage examples, see: 15 | # 16 | # http://www.perlmonth.com/features/ldap/ldap.html?issue=11 17 | # http://theoryx5.uwinnipeg.ca/CPAN/data/perl-ldap/Net/LDAP/Examples.html 18 | # 19 | # Some significant limitations of the code sample below include: 20 | # 21 | # - It is a simple, procedural script. You'd likely want to break out 22 | # several of its functions into individual subroutines. 23 | # 24 | # - It performs only primitive error handling. (It just dies and displays 25 | # an error message when an error occurs.) 26 | # 27 | # - It doesn't automatically try any alternate directory servers 28 | # if the primary server is unavailable. 29 | # 30 | # - It performs an "anonymous" bind to the directory. 31 | # 32 | # In some cases, your application might need to bind (authenticate) 33 | # to the CalNet directory as a specific user, rather than anonymously. 34 | # You'd need to do so, for instance, to access non-public attributes of 35 | # campus people, such as their CalNet IDs or student IDs. 36 | # 37 | # (Note: to access such non public-attributes, you'll first need to 38 | # obtain the appropriate permissions from the CalNet System's 39 | # administrators and often also from the campus department[s] which 40 | # own that data.) 41 | # 42 | # Here is an example of how you would bind to the directory as a specific 43 | # user, from Mark Wilcox's article on www.pearlmonth.com (above): 44 | # 45 | # my $mesg = $ldap->bind('uid=myuid,ou=people,dc=berkeley,dc=edu', 46 | # password => 'password'); 47 | # 48 | # In addition, when binding as a specific user, your application's 49 | # connection to the directory should be made using SSL. This way, 50 | # your directory user password and the non-public data you are 51 | # receiving will be encrypted when being sent over the network. 52 | # 53 | # For more information about how to use Perl-LDAP to connect to the 54 | # directory using SSL encryption, see the documentation for the 55 | # Net::LDAPS module, which is included with the Perl-LDAP distribution: 56 | # 57 | # http://perl-ldap.sourceforge.net/doc/Net/LDAPS.html 58 | # 59 | # The additional prerequisites for using Perl-LDAP with SSL appear to be: 60 | # 61 | # OpenSSL: http://www.openssl.org/ 62 | # Net::SSLeay: http://www.bacus.pt/Net_SSLeay/index.html 63 | 64 | use Net::LDAPS; 65 | 66 | # --------------------------------------------------------------- 67 | 68 | # Accept a single command line parameter, the 'uid' attribute that 69 | # uniquely identifies 'people' entries in the CalNet Directory Service 70 | #$uid = $ARGV[0] || 3877; 71 | 72 | # Convenience placeholder if we want to repeatedly test with a specific uid 73 | # $uid = "3877"; // Replace this uid with the one you would like to test 74 | 75 | $name = $ARGV[0]; 76 | #$uid = '172095'; 77 | 78 | # Define variables 79 | # ---------------- 80 | # LDAP directory to contact 81 | $directoryURL = "caldir.berkeley.edu"; 82 | #$directoryURL = "manzanita.berkeley.edu"; 83 | # $directoryURL = "pongo.berkeley.edu"; // alternate server 84 | 85 | $LDAPBIND = 'uid=YourAppBind,ou=Directory Administrators,dc=berkeley,dc=edu'; 86 | $LDAPPWD = 'YourAppPassword'; 87 | 88 | 89 | # Portion of the directory we'll be searching 90 | $searchBase = "ou=people,dc=berkeley,dc=edu"; 91 | 92 | # The attributes (and their associated values) that we wish to 93 | # search for in the directory. 94 | # 95 | # In this instance, we're searching for the directory entry 96 | # which matches a specific 'uid'. 97 | # 98 | # If we were searching for entries by name, for instance, 99 | # we could instead search on the common name (cn) attribute, 100 | # such as "(cn=John*Doe)", or the surname (sn) attribute, 101 | # such as "(sn=Doe)" ... 102 | #$searchFilter = "(uid=$uid)"; 103 | $searchFilter = "(cn=$name)"; 104 | 105 | print "Searching for name ", $name; 106 | 107 | # The attributes we'd like to have returned for each entry 108 | # 109 | # (Doing this is entirely optional; it simply reduces the 110 | # volume of data returned by excluding attributes that we're 111 | # not interested in receiving.) 112 | $attributesToReturn = [ 113 | 'dn', 114 | 'uid', 115 | 'displayName', 116 | 'mail', 117 | 'telephoneNumber', 118 | 'ucbadrdept1', 119 | 'ucbadrdept1name' 120 | ]; 121 | 122 | # Connect to the directory 123 | # ------------------------ 124 | print "Connecting to LDAP server \"$directoryURL\" ...\n"; 125 | 126 | # Open a connection to the directory 127 | #$ldaps = Net::LDAPS->new($directoryURL, 128 | # verify => 'require', 129 | # capath => '/home/jgm/authtest/caldir-pem', 130 | # ) # as struct 131 | # or die "$@"; 132 | 133 | #print "Connected"; 134 | 135 | # for ruby version see ruby-ldap.sourceforge.net/rdoc/ under ldap:sslconn 136 | 137 | $ldaps = Net::LDAPS->new($directoryURL) # as struct 138 | or die "$@"; 139 | 140 | # Make an anonyous bind to the directory 141 | # (See the comments above if you wish to bind to the 142 | # directory as a specific user.) 143 | 144 | $ldaps->bind; 145 | 146 | #$ldaps->bind("$LDAPBIND", 147 | # password => "$LDAPPWD"); 148 | 149 | #print "Looking up directory data for uid \"$uid\" ...\n"; 150 | 151 | # Perform a search 152 | # ---------------- 153 | $searchResultsObject = $ldaps->search 154 | ( 155 | # Search the 'people' portion of the directory, 156 | # as defined above 157 | base => $searchBase, # Note the comma here 158 | 159 | # Search on the uid attribute 160 | filter => $searchFilter, # and here 161 | 162 | # Return only a limited set of attributes from 163 | # the search, *if* we've defined such a set above 164 | attrs => $attributesToReturn 165 | ); 166 | 167 | # If there is a result code (indicating an error), 168 | # display an error message 169 | if ($searchResultsObject->code) { 170 | print "An error occurred during the LDAP search attempt:\n"; 171 | die $searchResultsObject->error; 172 | } 173 | 174 | # Disconnect from the directory 175 | # ----------------------------- 176 | $ldaps->unbind; 177 | 178 | # Work with the data returned from the search 179 | # ------------------------------------------- 180 | my $countOfEntriesReturned = $searchResultsObject->count; 181 | 182 | print "Search returned $countOfEntriesReturned entries ...\n\n"; 183 | 184 | # Cycle through each of the directory entries returned from the 185 | # search, and extract and print the values of selected attributes 186 | # of each entry 187 | for ( my $index = 0 ; $index < $countOfEntriesReturned; $index++) 188 | { 189 | # Look at each of the 'entry' objects returned from the search 190 | my $entry = $searchResultsObject->entry($index); 191 | 192 | # Initialize each variable each time through the loop 193 | $displayName = ""; 194 | $uid = 0; 195 | $eMailAddress = ""; 196 | $phoneNumber = ""; 197 | $dept1Name = ""; 198 | $dept1 = ""; 199 | 200 | # Extract the values from selected attributes 201 | $dn = $entry->get_value('dn'); 202 | $uid = $entry->get_value('uid'); 203 | $displayName = $entry->get_value('displayName'); 204 | $eMailAddress = $entry->get_value('mail'); 205 | $phoneNumber = $entry->get_value('telephoneNumber'); 206 | 207 | $dept1Name = $entry->get_value('ucbadrdept1name'); 208 | $dept1 = $entry->get_value('ucbadrdept1'); 209 | if ($dept1Name) 210 | { $departmentName = $dept1Name; } 211 | else 212 | { $departmentName = $dept1; } 213 | 214 | print " Distinguished Name: $dn\n"; 215 | print " UID: $uid\n"; 216 | print " Name: $displayName\n"; 217 | print " Dept: $departmentName\n"; 218 | print "E-mail: $eMailAddress\n"; 219 | print " Phone: $phoneNumber\n"; 220 | print "\n"; 221 | } 222 | 223 | 224 | 225 | -------------------------------------------------------------------------------- /googlecode_upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2006, 2007 Google Inc. All Rights Reserved. 4 | # Author: danderson@google.com (David Anderson) 5 | # 6 | # Script for uploading files to a Google Code project. 7 | # 8 | # This is intended to be both a useful script for people who want to 9 | # streamline project uploads and a reference implementation for 10 | # uploading files to Google Code projects. 11 | # 12 | # To upload a file to Google Code, you need to provide a path to the 13 | # file on your local machine, a small summary of what the file is, a 14 | # project name, and a valid account that is a member or owner of that 15 | # project. You can optionally provide a list of labels that apply to 16 | # the file. The file will be uploaded under the same name that it has 17 | # in your local filesystem (that is, the "basename" or last path 18 | # component). Run the script with '--help' to get the exact syntax 19 | # and available options. 20 | # 21 | # Note that the upload script requests that you enter your 22 | # googlecode.com password. This is NOT your Gmail account password! 23 | # This is the password you use on googlecode.com for committing to 24 | # Subversion and uploading files. You can find your password by going 25 | # to http://code.google.com/hosting/settings when logged in with your 26 | # Gmail account. If you have already committed to your project's 27 | # Subversion repository, the script will automatically retrieve your 28 | # credentials from there (unless disabled, see the output of '--help' 29 | # for details). 30 | # 31 | # If you are looking at this script as a reference for implementing 32 | # your own Google Code file uploader, then you should take a look at 33 | # the upload() function, which is the meat of the uploader. You 34 | # basically need to build a multipart/form-data POST request with the 35 | # right fields and send it to https://PROJECT.googlecode.com/files . 36 | # Authenticate the request using HTTP Basic authentication, as is 37 | # shown below. 38 | # 39 | # Licensed under the terms of the Apache Software License 2.0: 40 | # http://www.apache.org/licenses/LICENSE-2.0 41 | # 42 | # Questions, comments, feature requests and patches are most welcome. 43 | # Please direct all of these to the Google Code users group: 44 | # http://groups.google.com/group/google-code-hosting 45 | 46 | """Google Code file uploader script. 47 | """ 48 | 49 | __author__ = 'danderson@google.com (David Anderson)' 50 | 51 | import httplib 52 | import os.path 53 | import optparse 54 | import getpass 55 | import base64 56 | import sys 57 | 58 | 59 | def get_svn_config_dir(): 60 | """Return user's Subversion configuration directory.""" 61 | try: 62 | from win32com.shell.shell import SHGetFolderPath 63 | import win32com.shell.shellcon 64 | except ImportError: 65 | # If we can't import the win32api, just use ~; this is right on unix, and 66 | # returns not entirely unreasonable results on Windows. 67 | return os.path.expanduser('~/.subversion') 68 | 69 | # We're on Windows with win32api; use APPDATA. 70 | return os.path.join(SHGetFolderPath(0, win32com.shell.shellcon.CSIDL_APPDATA, 71 | 0, 0).encode('utf-8'), 72 | 'Subversion') 73 | 74 | 75 | def get_svn_auth(project_name, config_dir): 76 | """Return (username, password) for project_name in config_dir.""" 77 | 78 | # Default to returning nothing. 79 | result = (None, None) 80 | 81 | try: 82 | from svn.core import SVN_AUTH_CRED_SIMPLE, svn_config_read_auth_data 83 | from svn.core import SubversionException 84 | except ImportError: 85 | return result 86 | 87 | realm = (' Google Code Subversion Repository' 88 | % project_name) 89 | 90 | # auth may be none even if no exception is raised, e.g. if config_dir does 91 | # not exist, or exists but has no entry for realm. 92 | try: 93 | auth = svn_config_read_auth_data(SVN_AUTH_CRED_SIMPLE, realm, config_dir) 94 | except SubversionException: 95 | auth = None 96 | 97 | if auth is not None: 98 | try: 99 | result = (auth['username'], auth['password']) 100 | except KeyError: 101 | # Missing the keys, so return nothing. 102 | pass 103 | 104 | return result 105 | 106 | 107 | def upload(file, project_name, user_name, password, summary, labels=None): 108 | """Upload a file to a Google Code project's file server. 109 | 110 | Args: 111 | file: The local path to the file. 112 | project_name: The name of your project on Google Code. 113 | user_name: Your Google account name. 114 | password: The googlecode.com password for your account. 115 | Note that this is NOT your global Google Account password! 116 | summary: A small description for the file. 117 | labels: an optional list of label strings with which to tag the file. 118 | 119 | Returns: a tuple: 120 | http_status: 201 if the upload succeeded, something else if an 121 | error occured. 122 | http_reason: The human-readable string associated with http_status 123 | file_url: If the upload succeeded, the URL of the file on Google 124 | Code, None otherwise. 125 | """ 126 | # The login is the user part of user@gmail.com. If the login provided 127 | # is in the full user@domain form, strip it down. 128 | if '@' in user_name: 129 | user_name = user_name[:user_name.index('@')] 130 | 131 | form_fields = [('summary', summary)] 132 | if labels is not None: 133 | form_fields.extend([('label', l.strip()) for l in labels]) 134 | 135 | content_type, body = encode_upload_request(form_fields, file) 136 | 137 | upload_host = '%s.googlecode.com' % project_name 138 | upload_uri = '/files' 139 | auth_token = base64.b64encode('%s:%s'% (user_name, password)) 140 | headers = { 141 | 'Authorization': 'Basic %s' % auth_token, 142 | 'User-Agent': 'Googlecode.com uploader v0.9.4', 143 | 'Content-Type': content_type, 144 | } 145 | 146 | server = httplib.HTTPSConnection(upload_host) 147 | server.request('POST', upload_uri, body, headers) 148 | resp = server.getresponse() 149 | server.close() 150 | 151 | if resp.status == 201: 152 | location = resp.getheader('Location', None) 153 | else: 154 | location = None 155 | return resp.status, resp.reason, location 156 | 157 | 158 | def encode_upload_request(fields, file_path): 159 | """Encode the given fields and file into a multipart form body. 160 | 161 | fields is a sequence of (name, value) pairs. file is the path of 162 | the file to upload. The file will be uploaded to Google Code with 163 | the same file name. 164 | 165 | Returns: (content_type, body) ready for httplib.HTTP instance 166 | """ 167 | BOUNDARY = '----------Googlecode_boundary_reindeer_flotilla' 168 | CRLF = '\r\n' 169 | 170 | body = [] 171 | 172 | # Add the metadata about the upload first 173 | for key, value in fields: 174 | body.extend( 175 | ['--' + BOUNDARY, 176 | 'Content-Disposition: form-data; name="%s"' % key, 177 | '', 178 | value, 179 | ]) 180 | 181 | # Now add the file itself 182 | file_name = os.path.basename(file_path) 183 | f = open(file_path, 'rb') 184 | file_content = f.read() 185 | f.close() 186 | 187 | body.extend( 188 | ['--' + BOUNDARY, 189 | 'Content-Disposition: form-data; name="filename"; filename="%s"' 190 | % file_name, 191 | # The upload server determines the mime-type, no need to set it. 192 | 'Content-Type: application/octet-stream', 193 | '', 194 | file_content, 195 | ]) 196 | 197 | # Finalize the form body 198 | body.extend(['--' + BOUNDARY + '--', '']) 199 | 200 | return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body) 201 | 202 | 203 | def upload_find_auth(file_path, project_name, summary, labels=None, 204 | config_dir=None, user_name=None, tries=3): 205 | """Find credentials and upload a file to a Google Code project's file server. 206 | 207 | file_path, project_name, summary, and labels are passed as-is to upload. 208 | 209 | If config_dir is None, try get_svn_config_dir(); if it is 'none', skip 210 | trying the Subversion configuration entirely. If user_name is not None, use 211 | it for the first attempt; prompt for subsequent attempts. 212 | 213 | Args: 214 | file_path: The local path to the file. 215 | project_name: The name of your project on Google Code. 216 | summary: A small description for the file. 217 | labels: an optional list of label strings with which to tag the file. 218 | config_dir: Path to Subversion configuration directory, 'none', or None. 219 | user_name: Your Google account name. 220 | tries: How many attempts to make. 221 | """ 222 | 223 | if config_dir != 'none': 224 | # Try to load username/password from svn config for first try. 225 | if config_dir is None: 226 | config_dir = get_svn_config_dir() 227 | (svn_username, password) = get_svn_auth(project_name, config_dir) 228 | if user_name is None: 229 | # If username was not supplied by caller, use svn config. 230 | user_name = svn_username 231 | else: 232 | # Just initialize password for the first try. 233 | password = None 234 | 235 | while tries > 0: 236 | if user_name is None: 237 | # Read username if not specified or loaded from svn config, or on 238 | # subsequent tries. 239 | sys.stdout.write('Please enter your googlecode.com username: ') 240 | sys.stdout.flush() 241 | user_name = sys.stdin.readline().rstrip() 242 | if password is None: 243 | # Read password if not loaded from svn config, or on subsequent tries. 244 | print 'Please enter your googlecode.com password.' 245 | print '** Note that this is NOT your Gmail account password! **' 246 | print 'It is the password you use to access Subversion repositories,' 247 | print 'and can be found here: http://code.google.com/hosting/settings' 248 | password = getpass.getpass() 249 | 250 | status, reason, url = upload(file_path, project_name, user_name, password, 251 | summary, labels) 252 | # Returns 403 Forbidden instead of 401 Unauthorized for bad 253 | # credentials as of 2007-07-17. 254 | if status in [httplib.FORBIDDEN, httplib.UNAUTHORIZED]: 255 | # Rest for another try. 256 | user_name = password = None 257 | tries = tries - 1 258 | else: 259 | # We're done. 260 | break 261 | 262 | return status, reason, url 263 | 264 | 265 | def main(): 266 | parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY ' 267 | '-p PROJECT [options] FILE') 268 | parser.add_option('--config-dir', dest='config_dir', metavar='DIR', 269 | help='read svn auth data from DIR' 270 | ' ("none" means not to use svn auth data)') 271 | parser.add_option('-s', '--summary', dest='summary', 272 | help='Short description of the file') 273 | parser.add_option('-p', '--project', dest='project', 274 | help='Google Code project name') 275 | parser.add_option('-u', '--user', dest='user', 276 | help='Your Google Code username') 277 | parser.add_option('-l', '--labels', dest='labels', 278 | help='An optional list of labels to attach to the file') 279 | 280 | options, args = parser.parse_args() 281 | 282 | if not options.summary: 283 | parser.error('File summary is missing.') 284 | elif not options.project: 285 | parser.error('Project name is missing.') 286 | elif len(args) < 1: 287 | parser.error('File to upload not provided.') 288 | elif len(args) > 1: 289 | parser.error('Only one file may be specified.') 290 | 291 | file_path = args[0] 292 | 293 | if options.labels: 294 | labels = options.labels.split(',') 295 | else: 296 | labels = None 297 | 298 | status, reason, url = upload_find_auth(file_path, options.project, 299 | options.summary, labels, 300 | options.config_dir, options.user) 301 | if url: 302 | print 'The file was uploaded successfully.' 303 | print 'URL: %s' % url 304 | return 0 305 | else: 306 | print 'An error occurred. Your file was not uploaded.' 307 | print 'Google Code upload server said: %s (%s)' % (reason, status) 308 | return 1 309 | 310 | 311 | if __name__ == '__main__': 312 | sys.exit(main()) 313 | --------------------------------------------------------------------------------