danigm's blog

danigm's picture

Hoy en día todo el mundo confía en el correo electrónico, todos confiamos en que los correos que nos llegan vienen realemente de quien dice que viene. Para el que no lo sepa, el correo electrónico no va autenticado, un correo es igual que una carta, el remitente lo pone quien lo envía, y en ningún paso del proceso se verifica la identidad del mismo.

¿Cómo envíar un correo con la dirección que yo quiera?

Hacer esto en linux es extremadamente sencillo. Para el envío de correo se utiliza el protocolo SMTP. El correo se envía desde servidores SMTP, si escribes un correo desde gmail, por ejemplo, se utiliza para mandar el correo uno de los servidores smtp de google.

Por lo tanto si queremos envíar correo desde nuestro ordenador tenemos que instalar un servidor smtp, como por ejemplo postfix (en debian/ubuntu/etc apt-get install postfix).

Cuando lo ejecutamos tenemos en el puerto 25 de nuestra máquina el servicio corriendo:


$netstat -punta | grep -i LISTEN
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN -

Con el servidor smtp hay muchas formas de envíar correos (telnet, mail, sendmail, cualquier cliente de correo, ...)

Voy a poner un ejemplo de script en python que envía un correo con una dirección de correo dada

  1. #!/usr/bin/python
  2. # pymail.py <a href="mailto:from@mail.com">from@mail.com</a> "to@mail.com;to2@mail.com;..." "subject" "message"
  3.  
  4. import sys
  5. import smtplib
  6.  
  7. if len(sys.argv) < 5:
  8. print 'pymail.py <a href="mailto:from@mail.com">from@mail.com</a> "to@mail.com;to2@mail.com;..." "subject" "message"'
  9. sys.exit()
  10.  
  11. fromm = sys.argv[1]
  12. to = sys.argv[2]
  13. subject = sys.argv[3]
  14. message = sys.argv[4]
  15.  
  16. msg = ('From: %(fromm)s\r\nTo: %(to)s\r\nSubject: '
  17. '%(subject)s\r\n%(message)s' % globals())
  18.  
  19. s=smtplib.SMTP("localhost")
  20. s.sendmail(fromm, to.split(';'), msg)

Yo por ejemplo me he envíado un correo desde google@google.com

python pymail.py "Google INK <google@google.com>" "Daniel García Moreno <danigm@gmail.com>" "Te voy a decir hola" "Hello world"

Y aquí está en mi correo.



correo

Cómo evitar esto
Si has recibido algún correo mío alguna vez habrás visto que casi siempre lleva un adjunto signature.asc, pues bien, eso es la firma del mensaje. Existen mecanismos como GnuPG para poder verificar que el mensaje viene de quien dice venir, incluso se puede cifrar el mensaje para que sólo el destinatario pueda leerlo (los correos van en claro de servidor a servidor por la red). Cualquier cliente de correo que se precie es capaz de firmar con pgp/gpg, verificar las firmas y cifrar (yo uso evolution). Si la firma es válida podemos estar seguros de que el mensaje viene de quien dice que viene, incluso podemos asegurar que no ha sido alterado.

Para crear y manejar tus claves gpg puedes utilizar seahorse en gnome.

Mi clave pública es: FE6A3613

danigm's picture

Hoy he hecho un dibujo de un pingüino navideño y de paso lo he grabado, le he puesto un poquito de música y lo he colgado en youtube.

Para grabarlo he usado gtk-recordmydesktop y luego con mencoder lo he transformado, escalado y le he puesto música de Rob Costlow.

Lo he realizado en Archlinux con mi dell xps1210 dibujando con inkscape y mi touchpad.

Aquí el vídeo:


Aquí el resultado:



pingu

danigm's picture

Hace ya algún tiempo comencé a versionar todos mis proyectos con bazaar. La mayoría de los cosillas que hago son pequeños proyectos que no tienen mucha continuidad en el tiempo y no tiene sentido que se publiquen en forjas al estilo de launchpad. Así que ya que tengo mi servidor virtual subo las ramas a mi servidor a través de bzr+ssh. Con bazaar montar un repositorio es tan fácil como hacer un bzr push a otra máquina en la que tengas una cuenta ssh.

Por lo tanto en mi servidor tengo una carpeta "/home/danigm/branchs" dentro de la cual están todos mis proyectos. Cada proyecto es una carpeta que es un repositorio bazaar o una rama. Con bazaar es posible hacer branch o checkout desde una rama cualquiera.

Por otra parte hace poco descubrí web.py que es lo que andaba buscando hace ya algún tiempo. Una forma simple de desarrollar páginas web en python, sin mega-framework que complican el trabajo más de lo que lo facilitan.

Juntando estas dos cosillas ayer me puse a desarrollar un pequeño visor de repositorios bzr basandome en la estructura que yo tengo en mi servidor y el resultado puede verse en http://repo.danigm.net:8000/projects.

bzr-viewer tiene las siguientes funcionalidades:

Puedes echar un vistazo en mi repositorio y te puedes bajar el código para ver un ejemplo de applicación simple con web.py.

danigm's picture

He añadido soporte para twitter en sweetgtk y arreglado una serie de bugs.

Ahora Se puede seguir twitter y/o sweetter al mismo tiempo y escribir comentarios en sweetter y/o twitter. He añadido unos checkbox y dependiendo de si tienes seleccionado sweetter o twitter o ambos se reciben los comentarios y se postea en la plataforma adecuada.

Aquí un screenshot de la nueva versión:



frontal

Además he arreglado el script install que era una guarrería y ahora se hacen las cosas de buena manera, llevando todo a /usr/share/sweetgtk y la configuración y la cache a $HOME/.sweetgtk de cada usuario, copiandose un skel si este directorio no existe.

Así pues todo aquel que intentó instalarse sweetgtk sin exito debe ejecutar el script ./uninstall de la versión que intentó instalar y borrar todo archivo que quede por ahí suelto, incluso $HOME/.sweetgtk, bajarse la nueva versión y ejecutar el nuevo script install como root que hará todo lo pertinente.

El script install debería funcionar en la mayoría de las distros GNU/linux y por tanto en el openmoko. Las dependencias y demás cosas están en el post anterior

sweetgk2.tgz

Por otro lado lo he empaquetado para debian/ubuntu y aquí está el paquete:
sweetgtk_2.0_i386.deb

Gracias por vuestra atención y a disfrutar del microblogging.

danigm's picture

Hacía ya tiempo que tenía pensado hacer una aplicación de escritorio para poder interactuar con sweetter, pero hasta hoy no me había puesto a hacer nada serio.

Consiste en una aplicación hecha en pygtk que tira del módulo que ya hice antes pysweetter (que se conecta a sweetter a través de xmlrpc de forma transparente).

El código se puede conseguir así:
bzr branch http://repo.danigm.net/sweetgtk

Está bajo el control de versiones bazaar

Aquí una captura de pantalla de la aplicación:



frontal

Y como es pygtk también funciona en el openmoko neo freerunner:



frontal

Todavía estoy desarrollandolo, estoy teniendo problemas con los threads porque me da "segmentation faults" de forma "aleatoria", tengo que arreglar eso :P

Edito (23/11/2008 21:40):

Creo que ya he solucionado el problema de los threads, y además he hecho algunos arreglos para que funcione también en windows.

Aquí un screenshot funcionando en windows:



frontal

Para que funciones en windows vista hay que instalar una serie de cosas:

  1. Instalar python 2.5: http://www.python.org/download/
  2. Instalar GTK-runtime: http://sourceforge.net/project/showfiles.php?group_id=98754
    http://sourceforge.net/project/showfiles.php?group_id=98754&package_id=1...
  3. Instalar pygtk: http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.12/
  4. Instalar gobject: http://ftp.gnome.org/pub/GNOME/binaries/win32/pygobject/2.14/
  5. Instalar pycairo: http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.4/

Y por cierto, para que funcione en linux también es necesario tener instalado todo lo anterior, pero normalmente en un escritorio gnome estará instalado, los paquetes para debian son:

python, python-gtk2, python-gobject, python-cairo, python-notify

Tengo pensado hacer un paquete un día de estos, mientras tanto se puede conseguir el código del repositorio o de aquí:
http://danigm.net/files/sweetgtk.tgz

danigm's picture

Hace ya algún tiempo se me planteó el problema de tener una serie de funciones que se tienen que ejecutar cuando ocurre algo (un evento) y me hice un pequeño modulo en python para cubrir ese asunto.

Me basé en lo que conocía de pygtk, señales y eventos, así pues el funcionamiento básico es que tú declaras un evento, asignas funciones a ese evento, y cuando lances una señal, todas las funciones asociadas a ese evento se lanzan.

Se puede instalar de forma simple así:

sudo easy_install events

Aquí un ejemplo de uso:

  1. from events import EventManager, Event
  2.  
  3. def func1(*args):
  4. print "Im the func1 with args: " + str(args)
  5.  
  6. def func2(*args):
  7. print "Im the func2 with args: " + str(args)
  8.  
  9. def func3(*args):
  10. print "Im the func3 with args: " + str(args)
  11.  
  12. # Creating the eventManager
  13. em = EventManager()
  14.  
  15. # Create some events
  16. event1 = Event('event1')
  17. event2 = Event('event2')
  18.  
  19. em.add_event(event1)
  20. em.add_event(event2)
  21.  
  22. # Connecting functions with events
  23. em.connect('event1', func3, [1,2])
  24. em.connect('event1', func2)
  25. em.connect('event2', func1)
  26.  
  27. # Sending signals
  28. print "sending event1..."
  29. em.signal('event1')
  30. print "sending event2..."
  31. em.signal('event2')
  32.  
  33. # sending signal with arguments
  34. print "sending event1 with arguments..."
  35. em.signal('event1', [1,2,3])

Aquí está el código del módulo:

  1. class Event:
  2. def __init__(self, name):
  3. self.name = name
  4. self.listeners = {}
  5.  
  6. def add(self, function, data=None):
  7. self.listeners[function] = data
  8.  
  9. def delete(self, function):
  10. self.listeners.pop(function)
  11.  
  12. def called(self, data=None):
  13. for function, d in self.listeners.items():
  14. if data is None:
  15. if d is None:
  16. function()
  17. else:
  18. if type(d) == type([]):
  19. function(*d)
  20. elif type(d) == type({}):
  21. function(**d)
  22. else:
  23. function(d)
  24. else:
  25. if type(data) == type([]):
  26. function(*data)
  27. elif type(data) == type({}):
  28. function(**data)
  29. else:
  30. function(data)
  31.  
  32.  
  33. class EventManager:
  34. def __init__(self):
  35. self.events = {}
  36.  
  37. def add_event(self, Event):
  38. self.events[Event.name] = Event
  39.  
  40. def del_event(self, Event):
  41. self.events.pop(Event.name)
  42.  
  43. def connect(self, event, function, data=None):
  44. self.events[event].add(function, data)
  45.  
  46. def disconnect(self, event, function):
  47. self.events[event].delete(function)
  48.  
  49. def signal(self, event, data=None):
  50. if data is None:
  51. self.events[event].called()
  52. else:
  53. self.events[event].called(data)

danigm's picture

Como todo ser humano tengo una gran lista de cosas por hacer, también llamada TO-DO list. Hace algún tiempo empecé a utilizar tomboy para tomar notas y tener apuntado cosas por hacer, pero nunca me acuerdo de mirarlo, por lo tanto el otro día decidí hacer un sencillo script que cada cierto tiempo me recordara mi TO-DO list.

Para conseguirlo he utilizado pynotify para mostrar un mensajito en el escritorio cada 10 minutos, y he realizado consultas al servicio DBUS que ofrece tomboy para encontrar la nota con título TODO y coger el texto que hay en esta.

La idea es lanzar este script al iniciar el escritorio para así tenerlo en segundo plano mostrando mensajitos cada cierto tiempo.

Luego pensé que podía hacer lo mismo con los TODO de sweetter.net. Así que lo he integrado con el script utilizando el modulo pysweetter que tira del servicio XML-RPC. Por otra parte he tenido que implementar una función especifica para el servicio xmlrpc de sweetter.

Aquí una imagen del tema en acción:



frontal

Y para quien esté interesado, aquí está el código:

  1. #!/usr/bin/python
  2.  
  3. import gtk, pygtk
  4. pygtk.require('2.0')
  5.  
  6. import dbus
  7. import gobject
  8. import time
  9. import pynotify
  10.  
  11. from pysweetter import Sweetter
  12.  
  13. session_bus = dbus.SessionBus()
  14. uri = 'org.gnome.Tomboy'
  15. path = '/org/gnome/Tomboy/RemoteControl'
  16. sleep_time = 10 * 60
  17.  
  18. pynotify.init("Tomboy TODO notification")
  19. USER = 'danigm'
  20.  
  21. while True:
  22. try:
  23. tomboy = session_bus.get_object(uri, path)
  24. note_uri = tomboy.FindNote('TODO')
  25. all_text = tomboy.GetNoteContents(note_uri)
  26. all_text = all_text.split('\n')
  27. except:
  28. all_text = []
  29.  
  30. try:
  31. s = Sweetter()
  32. todo_list = s.get_TODO_list(USER)
  33. all_text.append('\nSweetter TODO\n')
  34.  
  35. for i, sweet in enumerate(todo_list):
  36. todo = '%d <a href="http://sweetter.net/%s?todo=1">%s</a>' % (i+1, USER, sweet.sweet)
  37. all_text.append(todo)
  38. except:
  39. pass
  40.  
  41. note = pynotify.Notification("TODO list",
  42. '\n'.join(all_text[1:]))
  43.  
  44. helper = gtk.Button()
  45. icon = helper.render_icon(gtk.STOCK_FILE,
  46. gtk.ICON_SIZE_DIALOG)
  47. note.set_icon_from_pixbuf(icon)
  48.  
  49. note.set_timeout(30000)
  50. note.show()
  51.  
  52. time.sleep(sleep_time)

Y para los más curiosos todavía aquí un repositorio del código:
bzr branch http://repo.danigm.net/todo-reminder

Los parches y comentarios son bienvenidos.

danigm's picture

Cuando se trabaja en una empresa es un tema recurrente el cálculo de tiempo dedicado a cada proyecto por parte del desarrollador.

Hay diferentes formas de hacerlo. La más simple sería mirando el reloj y haciendo un cálculo apróximado, el problema es que no tienes un registro de lo que has hecho.

Para el tracking de tiempo dedicado a un proyecto hay diferentes herramientas. Yo conocía gnotime que vale para lo que es, pero que no acaba de convencer.

Luego conocí Hamster, que es mucho más amigable, hace gráficas, informes y muchas polladas.

Yo en mi escritorio siempre tengo una terminal abierta, y últimamente me estoy dando cuenta de que las interfaces gráficas quitan mucho tiempo cuando no las necesitas, así que ayer decidí implementarme un time tracker de estos pero para terminal.

¿Cómo? Cojo python + vim, un poquito de sqlobject, se agita y aquí tenemos "Terminal Time Tracker".

En realidad son tres ficheros, aunque le he un instalador y desinstalador y polladas para que sea más simple de usar.

tttdb.py Una tabla para la base de datos.

  1. # Author: Daniel Garcia <dani@danigm.net>
  2. # License: GPLv3
  3.  
  4. from sqlobject import *
  5. import os
  6.  
  7. class Tracker(SQLObject):
  8. project = StringCol()
  9. task = StringCol()
  10. ticket = IntCol()
  11. start = DateTimeCol()
  12. end = DateTimeCol()
  13.  
  14. def get_hub():
  15. connection_string = 'sqlite://%s/devdata.sqlite' % os.getcwd()
  16. connection = connectionForURI(connection_string)
  17. sqlhub.processConnection = connection
  18.  
  19. return sqlhub
  20.  
  21. def create_db():
  22. # You need to create the database before.
  23. sqlhub = get_hub()
  24.  
  25. Tracker.createTable()

ttt.py Toda la chicha

  1. #!/usr/bin/python
  2.  
  3. # Author: Daniel Garcia <dani@danigm.net>
  4. # License: GPLv3
  5.  
  6. import datetime
  7. import time
  8. import sys
  9. import tttdb as db
  10. from tttdb import Tracker
  11.  
  12. sqlhub = db.get_hub()
  13.  
  14. def parse_time(time_seconds):
  15. hour = 0
  16. min = 0
  17. sec = time_seconds
  18. while sec >= 60:
  19. min += 1
  20. sec -= 60
  21. while min >= 60:
  22. hour += 1
  23. min -= 60
  24. time_str = '%02d:%02d:%02d' % (hour, min, sec)
  25. return time_str
  26.  
  27. def track(task, project='', ticket=0):
  28. today = datetime.datetime.now()
  29. tick = time.time()
  30. time_pass = 0
  31. try:
  32. while True:
  33. tick2 = time.time()
  34. time_pass = tick2 - tick
  35. cadena = '\rtracking: %(task)s %(project)s %(ticket)s %(time)s' % \
  36. {'time':parse_time(time_pass),
  37. 'task':task,
  38. 'project':project,
  39. 'ticket':ticket}
  40. sys.stdout.write(cadena)
  41. sys.stdout.flush()
  42. time.sleep(0.5)
  43. except:
  44. print '\n', 'Finalizando'
  45. end = datetime.datetime.now()
  46. db.Tracker(project=project,
  47. task=task,
  48. ticket=ticket,
  49. start=today,
  50. end=end)
  51.  
  52. def show(trackers):
  53. grouped = {}
  54. total = 0
  55. prev = ''
  56. for i in trackers:
  57. diff = i.end - i.start
  58. total += diff.seconds
  59. time_passed = parse_time(diff.seconds)
  60.  
  61. key = (i.task, i.project)
  62. if grouped.has_key(key):
  63. grouped[key] += diff.seconds
  64.  
  65. else:
  66. grouped[key] = diff.seconds
  67.  
  68. to_show = '%s | %-20s | %-40s | #%-6d | %s'
  69. to_show = to_show % (i.start.ctime(), i.project, i.task, i.ticket, time_passed)
  70. if prev != to_show[0:3]:
  71. prev = to_show[0:3]
  72. print ''
  73. print to_show
  74.  
  75. print ''
  76. for k,v in grouped.items():
  77. task, project = k
  78. time_passed = parse_time(v)
  79. print 'Tiempo para %-40s %s' % ('"'+task+'":', time_passed)
  80.  
  81. print '\nTotal: %s' % parse_time(total)
  82.  
  83. def show_today(delta=0):
  84. today = datetime.datetime.now() - datetime.timedelta(delta)
  85. yesterday = datetime.datetime(today.year, today.month, today.day)
  86. today_trackers = Tracker.select(Tracker.q.start > yesterday)
  87. show(today_trackers)
  88.  
  89. def show_project(project):
  90. project_trackers = Tracker.select(Tracker.q.project == project)
  91. sum = 0
  92. for i in project_trackers:
  93. sum += (i.end - i.start).seconds
  94.  
  95. print 'Tiempo para "%s": %s' % (project, parse_time(sum))
  96.  
  97. def show_all():
  98. all = Tracker.select()
  99. show(all)
  100.  
  101. def show_week():
  102. show_today(6)
  103.  
  104. def show_week_grouped():
  105. show_today_grouped(6)
  106.  
  107. def show_today_grouped(delta=0):
  108. today = datetime.datetime.now() - datetime.timedelta(delta)
  109. yesterday = datetime.datetime(today.year, today.month, today.day)
  110. today_trackers = Tracker.select(Tracker.q.start > yesterday)
  111. show_grouped(today_trackers)
  112.  
  113. def show_grouped(trackers):
  114. projects = {}
  115. total = 0
  116. for i in trackers:
  117. diff = (i.end - i.start).seconds
  118. total += diff
  119. if projects.has_key(i.project):
  120. projects[i.project] += diff
  121. else:
  122. projects[i.project] = diff
  123.  
  124. print ''
  125. for k,v in projects.items():
  126. p = '"' + k + '":'
  127. print 'Tiempo para %-20s %s' % (p, parse_time(v))
  128.  
  129. print '\nTotal: %s' % parse_time(total)
  130.  
  131. if __name__ == '__main__':
  132. help = '''
  133. %s tarea [proyecto] [ticket]
  134. '''
  135.  
  136. task, project, ticket = '','',0
  137. args = sys.argv[1:]
  138. if ('-h' in args) or ('--help' in args) or (len(args) == 0):
  139. print help % sys.argv[0]
  140. sys.exit()
  141. if len(args) >= 1:
  142. task = args[0]
  143. if len(args) >= 2:
  144. project = args[1]
  145. if len(args) >= 3:
  146. ticket = int(args[2])
  147.  
  148. track(task, project, ticket)

show.py Para ver el registro

  1. #!/usr/bin/python
  2.  
  3. # Author: Daniel Garcia <dani@danigm.net>
  4. # License: GPLv3
  5.  
  6. import sys
  7. import ttt
  8.  
  9. if __name__ == '__main__':
  10. help = '''
  11. %s [opcion]
  12.  
  13. opciones:
  14. -g muestra agrupados por proyecto
  15. -w muestra la ultima semana
  16. -gw muestra la ultima semana agrupado por proyecto
  17. -a muestra todo
  18.  
  19. si no se especifica opcion muestra las tareas de hoy
  20. '''
  21. args = sys.argv[1:]
  22. if ('-h' in args) or ('--help' in args):
  23. print help % sys.argv[0]
  24.  
  25. elif '-g' in args:
  26. # show grouped by project
  27. ttt.show_today_grouped()
  28. elif '-w' in args:
  29. ttt.show_week()
  30. elif '-gw' in args:
  31. # show grouped by project
  32. ttt.show_week_grouped()
  33. elif '-a' in args:
  34. ttt.show_all()
  35. else:
  36. ttt.show_today()

El código se puede pillar de mi repositorio personal:

  bzr branch http://repo.danigm.net/ttt

O del fichero tar.gz que adjunto aquí.

Para usarlo, tienes que tener instalado sqlobject y se instalaría ejecutando el script install.sh (hace una llamada a un comando con sudo). Esto te crea un directorio en $HOME/.ttt donde mete la base de datos y los scripts en python, y además copia t3 y t3show a /usr/local/bin para que puedas ejecutar los comandos sin modificar tu path.

Se usa de la siguiente manera:

  t3 "Escribiendo un post"

Y en la terminal se muestra el tiempo que vas dedicando a esta tarea. Para terminar tan solo hay que pulsar ctrl+c.
Además de una tarea se puede especificar un proyecto y un número para referenciarlo en el sistema de tickets que uses.

sintaxis:
  t3 tarea [proyecto] [ticket]
  t3 -h
ejemplo:
  t3 "plugin para jisko" "sweetter" 235879

Y para mostrar el resultado se usa t3show

Wed Sep 24 20:34:01 2008 | ttt                  | publicando                               | #0      | 00:00:06
Wed Sep 24 20:34:04 2008 | sweetter             | plugin para jisko                        | #235879 | 00:00:08
Wed Sep 24 20:34:18 2008 | ttt                  | publicando                               | #0      | 00:00:05

Tiempo para "plugin para jisko":                     00:00:08
Tiempo para "publicando":                            00:00:11

Total: