Un des problèmes avec la gestion des mails maison, c’est qu’on a vite fait d’être considéré comme un spam par un filtre un peu trop difficile. Très gênant si vous pensiez gérer votre adresse professionnelle. Heureusement il existe des solutions. J’ai mis à jour la page de mon wiki concernant la gestion des mails avec reverse DNS, SPF et DKIM. Voici un résumé :

Les filtres

Le principe des filtres anti-spam (dont SpamAssassin est le plus connu) est très simple. Vous partez d’un score de zéro. Lorsque le filtre détecte quelque chose de suspect votre score augmente, lorsque vous avez un comportement que n’aurait pas un spammeur, vous perdez des points. Arrivé à une certaine limite, vous devenez un spam.

Évidement toute la difficulté réside à bien pondérer et trouver les bons critères. Le fait d’utiliser des mots comme « viagra » va vous faire gagner des points. Les spammeurs l’ayant comprit, ils utiliseront v1agra par exemple. Les critères faisant perdre des points ne doivent pas non plus être simples sinon un spammeur les utilisera pour passer inaperçu.

Il existe également le filtre bayésien plus complexe mais très puissant qui va utiliser des probabilités statistiques. Ce filtre se base sur le contenu du message et l’on a donc pas d’influence coté serveur. Évitez juste de parler de vente de médicaments en ligne dans vos messages.

Voici deux exemples de scores (spamassassin et un inconnu) plutôt mauvais que j’ai eu sans rien activer :

X-SGSI-SpamCheck: n'est pas un polluriel, SpamAssassin (score=1.982,requis 5,
 BAYES_50 1.00, RDNS_DYNAMIC 0.98, SPF_HELO_PASS -0.00)

Il s’agit du filtre de mon université, il considère que l’on est un spam à partir de 5 et m’a mit 1.982, rien de dramatique.

X-Spam-Flag: YES
X-Spam-Score: 6.782
X-Spam-Level: ******
X-Spam-Status: Yes, score=6.782 tagged_above=4 required=6.3
	tests=[BAYES_50=0.8, EIGHTBIT_ENCODING=1, RCVD_FAKED_HELO=2,
	RCVD_SHORT_HELO=2, RDNS_DYNAMIC=0.982] autolearn=no

Il s’agit ici d’un filtre d’entreprise qui est beaucoup plus sévère. Il m’a mit un score de 6.782 alors que sa tolérance est à 6.3. Cela a eu pour effet de mettre un gros ***SPAM*** dans le sujet du message.

« Capitaine, je crois que notre filtre SpamAssassin est un peu trop permissif… »

Reverse DNS

La résolution DNS classique est de faire correspondre une URL à une IP. Le reverse DNS est le chemin inverse. Par défaut, j’ai, dans le cas de mon serveur OVH, 178-33-111-174.kimsufi.com pour l’IP 178.33.111.174. C’est ça qui explique mon « bonus » RDNS_DYNAMIC 0.98.

En mettant votre nom de domaine à la place, le problème est réglé. Vous pouvez vérifier que vous avez la bonne valeur via la commande $ dig -x 11.22.33.44 dans le champ PTR. J’ai remarqué que certains serveurs prenaient beaucoup de temps à mettre à jour leurs reverse DNS donc prenez votre mal en patience.

Si vous possédez comme moi plusieurs domaines pointant sur la même IP, sachez qu’il est inutile de mettre plusieurs entrées DNS PTR, cela pourrait être même contre productif. [Source]

SPF

Le plus simple. SPF pour Sender Policy Framework est simplement une entrée DNS depuis quel domaine on peut envoyer un email. Dans le cas d’un seul domaine qui n’envoie que depuis ses entrées MX, l’entrée DNS est

mart-e.be    SPF    v=spf1 mx ~all

Vous pouvez ainsi spécifier d’autres serveurs (si par exemple vous utilisez le relais SMTP de votre FAI). Pour les cas plus complexes, je vous renvoie vers le site officiel.

La valeur ajoutée par cette règle est assez faible. J’ai eu droit à SPF_HELO_PASS -0.00 pour le premier serveur mail et SPF_HELO_PASS=-0.001,SPF_PASS=-0.001 pour le deuxième. Vous pouvez vous dire que l’intérêt est donc limité mais voyez plutôt comme ceci : si un jour quelqu’un essaye d’envoyer du spam en se faisant passer pour vous, la vérification SPF échouera et son score de spam augmentera de façon non-négligeable.

Attention: SPF casse la redirection. Si vous envoyez un mail à machin@gmail.com sur laquelle votre correspondant a réglé une redirection automatique vers machin@myopera.com, c’est l’adresse IP de Google qui apparaîtra et pas la votre. La vérification SPF échouera donc. Cependant, ce n’est pas si grave que ça parce que le filtre anti-spam de Opera doit avoir l’habitude de recevoir tous les emails venant de machin@gmail.com qui a des bonnes chances d’être dans une liste blanche. Donc si le serveur du correspondant est bien fait, ça ne devrait pas poser de problèmes.

DKIM

Plus difficile, il s’agit ici de signer les headers du mail envoyé. La clef publique est spécifiée dans les DNS. J’ai choisi d’utiliser OpenDKIM. On génère des clefs asymétriques pour chaque domaine et on publie la clef publique dans les DNS. Celle pour ce domaine est par exemple :

1
default._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChUywElHkvIJwgp9BYce97yhv0ImwK5+2Jm0CHBCfjYpeV7pSaAh/aYmX9+BJcSupVnJYBPf4DT/AFbV7O6snG6rGf3bnJSHdfyGa7Zq8a/7ERdTYo6/W5LJvaenDAxqlWPlgVafQtncRt+4/iF133FXLpC4VL6NmbMirK0yMRKQIDAQAB"

Lorsque que vous signerez un email, on aura par exemple.

1
2
3
4
5
6
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mart-e.be; s=default;
    t=1353269228; bh=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=;
    h=Date:From:To:Subject:From;
    b=VQUjpDqQbD4OH4dRO5Ex3J0Qxoa5aKv6m7EYnxUgXE+SJd45PzJ0ZhIMzlIah3PRJ
 6UQX7rZizYU7gp6PioYFovADAW0o31iZYyTpuiUlEXpKAFeoRl0gR7wTNZrPdkSgSr
 A8bxxBjJPIUPpYW6ePuRixrumcCiNu2a0o8IC4Bk=

Votre correspondant supportant DKIM vérifiera la signature. Si elle est valide, vous perdez des points à votre score spam, si elle est invalide, vous en gagnez. Ben oui il ne suffit pas dire qu’on fait du DKIM pour ne pas être un spam, il faut encore bien le faire.

Conclusion

En appliquant ces trois méthodes, je suis passé à un score négatif sur le premier serveur et inférieur à 4 sur le deuxième (score à partir duquel il n’indique plus le détail).

Cela ne vous fera pas passer à travers les filtres les plus drastiques mais devrait diminuer le risque. N’hésitez pas à faire des tests sur plusieurs serveurs différents. Les filtres de Google et Yahoo ne donnent pas le détail du score mais les entreprises privées ou gens qui ont installé des filtres maisons sont plus sympa.

Si vous connaissez d’autres moyen de diminuer ce score, n’hésitez pas à partager. Je n’ai pas exemple pas d’explication sur le RCVD_FAKED_HELO et RCVD_SHORT_HELO qui m’ont donné chacun deux points ou le EIGHTBIT_ENCODING que je n’explique pas non plus (tu aurais préféré quoi ?) dans l’exemple ci-dessus.

Les nombreuses groupies qui visitent mon site par millions chaque jour (presque ça) ont sûrement remarqué que mart-e.be a été down pendant quelques jours, au grand désarrois de la touche F5 de leur clavier. La raison est simplement que mon blog et mes emails étaient hébergés chez Legtux, sur un serveur de online.net. Or ce week-end, Legtux ayant subit une attaque DDOS, online a eu la réaction très intelligente de bloquer le compte de Legtux. Ben oui, c’est évidement du à une mauvais gestion de la part de Legtux (alors que les solutions sont si simples -humour-). Situation désormais résolue avec une migration chez OVH (ça t’apprendra à mal traiter tes clients Online).

Bon pourquoi je vous raconte tout ça ? Parce que cet incident m’a poussé à faire quelque chose que j’aurais du faire depuis longtemps : gérer moi même mes mails (ce blog passera le cap dans un future plus ou moins proche)! J’ai prit il y a environ un an un serveur kimsufi chez OVH sur lequel j’héberge de nombreux services (XMPP, StatusNet, RSS, OpenID…), le but étant de gagner toujours plus d’indépendance, en particulier par rapport à Google. Et ce week-end, j’ai avancé d’un cran puisque j’ai configuré un beau serveur Postfix et Dovecot, le tout sans base de donnée.

Pour ceux qui aimeraient gérer eux aussi leurs emails, sachez qu’il existe énormément de méthodes. J’avais commencé en suivant la méthode de ®om (tutoriel de 2009 mais toujours valable) qui utilise également Postfix et Dovecot. Cependant, il y avait une chose qui me gênait : cette méthode était pensée pour la gestion d’un seul compte mail. On crée un utilisateur Unix, on stocke les emails dans ~/Maildir, on accède au compte mail avec ses identifiants. Je ne dis pas que cette méthode est mauvaise (elle est sans doute la meilleur si vous n’avez qu’un seul compte mail) mais je voulais quelque chose de plus souple qui me permette de gérer plusieurs noms de domaine sans devoir me rabattre sur MySQL.

Dovecot travaillant déjà de bon matin

La méthode que j’ai utilisée est assez proche de celle ®om mais utilise des adresses mail virtuelles. Tout est géré par un seul utilisateur selon une hiérarchie très simple: /home/vmail/example.com/bob pour bob@example.com, le mot de passes de bob étant géré par Dovecot dans un format similaire aux utilisateurs Unix (un fichier /etc/dovecot/passwd). Cela me permet facilement de créer des nouvelles adresses pour de nouveaux utilisateurs.

La méthode est très largement inspirée du tutoriel de ubuntu.com PostfixVirtualMailBoxClamSmtpHowto et j’ai traduite et ajoutée sur mon wiki tout neuf. Pour la marche à suivre, rendez vous donc sur wiki.mart-e.be/email. Si vous remarquez que j’ai oublié quelque chose, n’hésitez pas à me le signaler (ou contribuer, c’est un wiki après tout).

Cependant quelques limites à garder en tête en utilisant cette méthode :

  • Les mails sont stockés dans des fichiers texte lisibles par l’administrateur du serveur
  • La gestion des emails se fait par des scripts bash, pas pratique si vous voulez permettre la création de compte pour des externes (mais pas impossible)
  • Les mots de passes sont hashés mais pas salés (deux mots de passes égaux auront le même hash)

J’essayerai aussi d’ajouter la gestion du spam bientôt.

Gwibber est un client pour réseaux sociaux (StatusNet, Twitter & co) assez sympa. Seulement, il a un problème : sa base de donnée à tendance à augmenter au fur et à mesure du temps. Aujourd’hui le fichier ~/.config/gwibber/gwibber.sqlite faisait 132MB chez moi, c’est beaucoup pour gérer juste un flux Twitter et un StatusNet.

En fouillant un peu le code, j’ai trouvé la fonction de maintenance qui sert à supprimer les 2000 plus vieux status au démarrage. Seulement, les status ne sont pas la seule chose qui sont stockées dans la base de donnée, il y a aussi les liens, une crasse qui augmente vite. La preuve :

$ cd ~/.config/gwibber/
$ ls -lh gwibber.sqlite
-rw-r--r-- 1 mart users 132M Nov  2 12:34 gwibber.sqlite
$ sqlite3 gwibber.sqlite 
SQLite version 3.7.14.1 2012-10-04 19:37:12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select count(*) from messages where stream = 'links';
39622

Ouch 40000 liens stockés, pas étonnant que ça monte. J’avais ouvert un bug report à ce sujet là il y a plus de deux mois mais je n’ai eu aucune réponse. Tant pis, on est jamais mieux servi que par soit même de toute façon. On peut donc supprimer les plus vieux en modifiant un peu la commande (triviale) de la fonction de maintenance pour obtenir:

DELETE FROM messages WHERE operation = 'receive' AND stream = 'links' AND time IN (SELECT CAST (time AS int) FROM (SELECT time FROM messages WHERE operation = 'receive' AND stream = 'links' AND time != 0 ORDER BY time ASC LIMIT (SELECT COUNT(time) FROM messages WHERE operation = 'receive' AND stream = 'links' AND time != 0) - 2000) ORDER BY time ASC);

Après avoir lancé cette commande dans le shell sqlite, on purge le tout et tadaaaaam

sqlite> select count(*) from messages where stream = 'links';
3071
sqlite> VACUUM;

$ ls -lh gwibber.sqlite
-rw-r--r-- 1 mart users 41M Nov  2 12:37 gwibber.sqlite

41MB, pas mal le nettoyage. On peut même faire mieux en supprimant les autres types de status qui prennent un peu trop de place. Testez chez vous pour voir ce qui encombre le plus.

sqlite> select count(*), stream from messages group by stream;
4317|images
3084|links
4372|messages
44|private
6|profile
629|replies
39|send_thread
4703|user
1235|videos

Hmmm un peu trop d’images chez moi, ne gardons que les 1000 dernières.

sqlite> DELETE FROM messages WHERE operation = 'receive' AND stream = 'images' AND time IN (SELECT CAST (time AS int) FROM (SELECT time FROM messages WHERE operation = 'receive' AND stream = 'images' AND time != 0 ORDER BY time ASC LIMIT (SELECT COUNT(time) FROM messages WHERE operation = 'receive' AND stream = 'images' AND time != 0) - 1000) ORDER BY time ASC);
sqlite> VACUUM;

$ ls -lh gwibber.sqlite
-rw-r--r-- 1 mart users 34M Nov  2 13:11 gwibber.sqlite

Vous pouvez facilement jouer un peu avec la base de donnée en changeant les paramètres mais prudence. Je n’ai pas inspecté en long et en large la structure et cette façon de faire n’est peut être pas la plus propre (si vous avez beaucoup de lien par message, vous risquez d’en effacer trop par exemple). Mais bon, je n’avais pas envie de passer 2h là dessus et en sachant que je ne retourne rarement plus loin que les 100 derniers status, je ne prend pas trop de risque en nettoyant dans les 2000 derniers. À vous de voir… Vous pouvez aussi mettre les commandes dans un cron pour automatiser tout ça pour garder la base de donnée à une taille raisonnable.

Dernièrement, App.net a fait parler de lui pour avoir réussi sa levée de fond pour commencer son développement. Qu’est-ce qu’App.net? Sur leur site, voici ce qui est annoncé:

App.net is a real-time social feed without the ads.
Let’s create a service that puts users first.

App.net is a different kind of social platform.

We’re building a real-time social service where users and developers come first, not advertisers.

Pour résumer, l’idée derrière les développeurs de App.net est donc de créer un clone de Twitter payant. Pourquoi payer ? Pour garantir que les utilisateur et les développeurs soient les personnes à garder heureux et non plus le produit à rentabiliser comme Facebook et Twitter le considère trop souvent. L’idée a été lancée suite à la fermeture de l’API de Twitter et la présence de publicités grandissante.

Bon on a donc un système:

  • Centralisé
  • Payant
  • Propriétaire
  • Respectant les utilisateurs et développeurs

Waw quand j’ai entendu ça, j’y croyais pas. Les gens marcheraient jamais. Et pourtant, ils ont récolté 800.000$ à ce jour. En comparaison, c’est 4 fois plus que ce que Diaspora avait rassemblé pendant sa levée de fond (déjà impressionnante).

Pourquoi est-ce que je n’y croyais pas ? Parce qu’on a déjà OStatus/StatusNet ! Pour ceux qui débarquent, OStatus est un standard ouvert qui utilise une série de protocoles pour faire de l’échange de messages et StatusNet en est l’implémentation la plus connue (Friendica en est une autre). La particularité de StatusNet est d’être un logiciel libre, n’importe qui peut l’installer sur son serveur. Identi.ca est l’instance publique de StatusNet la plus connue mais il en existe des milliers d’autres, j’en ai une par exemple. Soit vous créé votre compte sur une instance existante, soit vous installez la votre sur votre serveur, cool non?

OStatus permet un échange de messages de façon distribuée. Avec ma petite instance minable, je peux parler avec n’importe qui d’autre ayant une instance compatible OStatus. Et c’est là toute la force du protocole de mon point de vue. Avec un système libre et distribué, on peut potentiellement avoir le meilleur système du monde (impossible à contrôler par exemple).

Et pourtant, aujourd’hui les gens sont prêt à rassembler 800.000$ pour créer un système payant, centralisé et propriétaire. Qu’est-ce que le système a de plus ? Qu’est-ce qui manque à StatusNet qui n’a pas réussi à se développer plus que ça?

Le buzz. App.net a réussi à faire parler de lui à un moment où il fallait, quand Twitter recevait le plus de critiques. Jusqu’à présent Twitter convenait parfaitement à tout le monde, seul quelques geeks avec leurs concepts dépassés de vie privée n’étaient pas content. Maintenant on empêche Instagram de fonctionner aussi bien qu’avant, on parle d’avoir de la pub, la censure commence à être trop présente, les mécontents augmentent. L’équipe de App.net a saisi le moment parfait pour sortir son projet avec des arguments très marketing. StatusNet n’a jamais réussi à se vendre ainsi.

Une entité claire. Savoir qu’il y a une compagnie avec des moyens derrière est rassurant pour l’utilisateur moyen. Il préfère passer par une compagnie commerciale qu’utiliser un serveur maintenu par des dons et quelques bénévoles qui risque de crasher ou être en surcharge à tout moment. L’argent ça fait pro, c’est tout. Quels sont les moyens derrière StatusNet? Aucune idée, juste un site officiel pas très fourni, un wiki spammé, un dépot Gitorious assez discret. Je n’ai aucune idée de comment avance StatusNet, ce qui se passe etc. Et OStatus? C’est encore pire. Site web mort, wiki vide (ah non, il y a cette page qui est intéressante). Je veux dire, est-ce qu’il y a un compte officiel OStatus ou StatusNet qui donne des annonces sur l’état du projet ?

Une bonne interface. Je ne suis pas un pro de l’IHM mais il faut quand même avouer que, aussi bien visuellement qu’à l’utilisation, Twitter est plus agréable. « C’est moche », « c’est lent », « c’est pas intuitif »,… On peut faire facilement pas mal de reproches (fondés ou non) à StatusNet. C’est con mais une interface intuitive avec des effets AJAX dans tous les coins, ça fait plaisir à l’œil. Vous avez vu l’alpha de App.net, si vous êtes en manque d’inspiration…

La centralisation. C’est triste à dire mais la centralisation a des avantages. Tout d’abord une plus grande réactivité. Pas de connexion et propagations de messages entre instances, tout est au même endroit. Également, la centralisation permet de créer un index très facilement des personnes présentes. Il n’existe pas de manière automatisée de chercher un groupe de personne sur StatusNet. Un index distribué serait-il possible ?

Vu comme un service. Lorsqu’il a été demandé aux fondateurs de App.net pourquoi ils ne sont pas open source, il a été répondu que leur but n’était pas de produire un logiciel mais un service. Ils se comparent à Dropbox qui fonctionne comme un service. L’utilisateur lambda n’est pas intéressé par ce qu’il y a derrière, il veut juste que ça fonctionne (ici l’on pourrait introduire un parallèle à Apple mais ce n’est pas le troll du jour). StatusNet est encore présenté trop souvent pour ses caractéristiques techniques (bien mais pas bandant) et non pas comme un outil de communication pour rapprocher les gens (là vous m’intéressez).

Je ne parlerai pas de l’API parce que je ne l’ai pas étudiée en détail mais il me semble que, du coté de StatusNet, il n’y a pas de quoi se plaindre (que les spécialistes me disent si je me trompe).

Je viens peut être de critiquer StatusNet et pourtant j’y crois encore, j’ai vraiment envie que ça fonctionne. Je crois encore que OStatus/StatusNet a un avenir devant lui. Je crois que tout n’est pas perdu et qu’il y a moyen d’attirer des masses. L’arguement principal avancé de app.net est qu’il respecte les utilisateurs et développeurs. Qu’est-ce qui respecte mieux les utilisateurs et développeurs qu’un outil créé par eux pour eux ? Un outil libre a un avantage énorme sur ce point, c’est nos données, on en fait ce qu’on veut.

App.net a montré que des gens sont prêt à repartir à zéro malgré l’effet réseau très fort sur Twitter. Qu’est ce qu’on peut faire pour y réussir également ? La question reste ouverte, je ne dis pas maintenir la vérité mais voici quelques points essentiels de mon point de vue:

  • Une interface retravaillée: on a le protocole, il manque le design (l’opposé de Diaspora en gros)
  • Une instance de référence fiable: identi.ca est ce qu’il y a de plus proche mais il manque encore de fiabilité et ne joue pas très bien avec les autres instances.
  • Un écosystème plus riche: l’API est très proche de Twitter, ça devrait faciliter les choses non? Créons des boutons « partager sur StatusNet », des clients mobiles, des intégrations dans des sites web…
  • En parler: StatusNet reste le coin des geeks, même mes potes en info ils connaissent pas en général.

Bon après il a des questions ouvertes. Est-ce qu’il faudrait un autre client alternatif à StatusNet ? Faut il chercher à copier Twitter à tout prix ou se différencier ?

Et à ceux qui me diront « t’as qu’a coder pour StatusNet plutôt que de critiquer », je rappelle qu’on peut critiquer (positivement) sans pouvoir forcement faire mieux soit même. Je suis très loin d’être un ninja du PHP, je suis mauvais et je le sais, je ne vais pas commencer à faire du développement là dedans. Par contre il y a sans doute d’autres contributions intéressantes et c’est là que j’aimerais créer une discussion.

Les ressources par exemple ? Vous avez quoi ? Allez je commence:
Si vous cherchez à jouer avec StatusNet en python, je vous conseille cette librairie python request-oauth (ou mon port python 3) pour utiliser l’API OAuth.

En terme de contributions, il y a cette page qui donne des pistes. Le wiki peut sans doute recevoir encore un peu d’aide (traduction en Français ?), trois pages Wikipédia qui pourraient bénéficier d’un petit rafraîchissement/éclaircissement OStatus, StatusNet, Identi.ca.

Si vous avez des chouettes ressources, librairies, outils, d’idées d’amélioration de StatusNet, je suis curieux d’entendre tout ça.

Mise à jour 17/08: vous avez lu les nouvelles conditions d’utilisations de l’API 1.1 de Twitter ? Il est plus que temps de se dégager de ça.

Aujourd’hui, mon flux RSS a vu passer quelques articles qui m’ont font sursauter. D’abord, j’ai vu ce post de Mike Conley, développeur chez Mozilla, No, that’s not it for Thunderbird. Apparemment des gens auraient mal compris une annonce au sujet de Thunderbird, je n’y prête pas plus attention que ça… Puis je vois un article chez Crowd42 Mozilla va arrêter le développement de Thunderbird. Woholaa manneke ! Article repris par m0le Thunderbird ne sera plus (retiré, a publié un erratum après discussion). Et puis le coup de grâce fut l’article de Denis Szalkowski L’arrêt de Thunderbird enfonce la crédibilité de l’Open Source ! (nuancé au conditionnel après discussion également) qui dit carrément que, je cite, « Linux n’est pas adapté pour la station de travail ». Bam !

Bon après je comprend ces réactions, c’est des chaînes de rumeurs qui s’amplifient à chaque pas. A ce rythme là, on se retrouve avec des forks agressifs dans 24h. Seulement revenons aux sources pour voir ce qui est réellement.

Techcrunch a publié un article That’s it for Thunderbird dans lequel ils dévoilent un mail confidentiel pour alerter les développeurs des publications en principes prévues pour lundi. Bon les gens, quand on dit « on fait ça pour vous tenir au courant, ne le rendez pas public », faut pas être con et arrêter de comprendre « si je publie ça le premier, je vais faire le buzz ». Merde quoi, vous voyez le résultat maintenant ? Les gens s’emballent pour un rien en lisant un mail de 15 lignes. Bon il y a quand même un passage intéressant dans le mail:

We’re not “stopping” Thunderbird, but proposing we adapt the Thunderbird release and governance model in a way that allows both ongoing security and stability maintenance, as well as community-driven innovation and development for the product. This will mean an eventual shift in how we staff Thunderbird at Mozilla Corporation – we are still working out details, but some people will likely end up on other Mozilla projects.

Donc le développement ne sera pas arrêté mais va se focaliser sur la sécurité et stabilité. Pas encore clair mais le staff risque de diminuer un peu après réattributions à d’autres projets.

Un peu plus tard, sans doute en réaction aux rumeurs qui grossissaient, Mitchell Baker, la chair de Mozilla Foundation, publie un article Thunderbird: Stability and Community Innovation. Dans cet article, elle explique que les utilisateurs de thunderbird sont globalement content de l’état actuel du logiciel. Et c’est vrai, il fonctionne bien, il gère bien les mails, il peut être étendu facilement par des addons, quoi de plus ? Son point est donc que la priorité n’est plus d’ajouter des nouvelles fonctionnalités mais de maintenir, stabiliser et sécuriser le client mail. Et c’est très bien, si Thunderbird devient un logiciel sans bug, qui fait très bien son boulot (gérer les emails, pas plus), je signe. La course aux nouvelles fonctionnalités c’est très gadget, juste histoire de montrer qu’on existe toujours et pas forcément essentiel. Les dernières en date ? La création de compte emails depuis l’interface et l’intégration de services tiers pour les grosses pièces jointes. Mouai pas mal mais pas forcement les choses qui vont changer la vie des utilisateurs. Sans doute que le client mail n’est pas, comme le navigateur, un logiciel qui a besoin sans cesse de nouvelles fonctionnalités et de grappiller des microsecondes de vitesse.

C’est une question de point de vue, ou bien on dit que les fonctionnalités ne sont plus une priorité ou bien on dit que la stabilité est la nouvelle priorité. Verre à moitié vide ou à moitié plein ?

Dans l’article, elle donne également le lien vers une page du wiki Mozilla Thunderbird/Proposal: New Release and Governance Model. Dans cette page on note que Thunderbird est utilisé par 20 millions de personnes (on arrête pas le développement d’un logiciel utilisé par 20 millions de personnes, sont pas con non plus), que les deux versions ESR (pour entreprises) et « normale » vont continuer leur rythme de release habituel (20 novembre pour la première, toutes les six semaines pour la deuxième) et que le modèle de fonctionnement actuel ne va pas changer globalement.

Pour en rajouter une couche, on a le témoignage de deux développeurs de Thunderbird (des gens qui savent ce qu’ils disent en gros). Mike Conley avec No, that’s not it for Thunderbird et Ludovic Hirlimann avec Thunderbird’s future from the inside qui disent que ça ne risque pas de changer grand chose pour l’utilisateur avant au moins la version 17.

Je ne sais pas vous, mais je pense qu’il n’y a aucune raison de s’inquiéter pour notre client mail favori. Le seul point qui m’ennuie est que j’aurais bien aimé voir Lightning (agenda) intégré officiellement et Mike Conley avait comme projet de retravailler le carnet d’adresse. Bon c’est pas la fin du monde et les addons existent toujours et ne risquent pas de disparaître, même si Mozilla ne touchait plus à une ligne de code de Thunderbird (ce qui, je le répète, n’est pas prêt d’être le cas). Le futur nous en dira plus.

Keep calm, don’t fork and love the pandas.

Mise à jour 8/7: un article officiel (enfin) a été publié sur le blog de Mozilla Adjusting the way Thunderbird is managed. On confirme le fait que la stabilité et sécurité sont les points les plus importants à ce jour. Ils disent également que, compte tenu des nombreux projets qu’ils ont en particulier le futur Boot2Gecko, ils vont diminuer un peu le nombre de développeurs pour les réattribuer. Le projet n’est pas abandonné, juste que pour l’instant les innovations viendront plutôt de la communauté. Ce n’est qu’une proposition qui ne prendra de toute façon pas effet avant septembre et doit être discutée. Rappel: c’est un projet open source, contribuez plutôt que de forker.

Également une interview de Jb Piacentino, le « managing director » de Thunderbird chez Tristan Nitot. Il explique que des releases sont prévues pour Thunderbird, encore une fois, pas de soucis.

Je possède un appareil photo numérique Canon PowerShot A530, un modèle datant de 2006, un de ces petits compact simple et efficace, « Point & Shoot » en Anglais. Quand je vois que certains smartphones (vous savez ces trucs qui deviennent intelligents parce qu’ils ont un écran tactile, un peu comme ces films qui deviennent bien en 3D) ont quasi 10 fois plus de megapixel que moi, on pourrait se dire qu’il est temps pour une upgrade. Que nenni ! On ne fera pas fonctionner la société de consommation inutilement. Sans dépenser un rond, on peut transformer son appareil bas de gamme en un appareil à en rendre jaloux un hipster. On va hacker notre appareil. Et aux gens qui répondrons « pourquoi faire ? », je répondrai « parce qu’on peut » (oui oui, je danse également comme ça quand un hack fonctionne).

CHDK, pour Canon Hack Developpement Kit, est un logiciel sous GPL à installer sur sa carte SD qui permettera d’augmenter les possibilités de l’appareil. On ne touche pas au firmware donc pas de risque de faire trop de dégât (presque, il est toujours possible de faire des bêtises si on fait un script foireux) et surtout formater la carte SD suffit à rendre l’appareil à son état d’origine. Ce kit est prévu pour une longue liste de Canon Point & Shoot. Si vous possédez une autre marque, ça ne sert à rien d’essayer, ça ne sera pas compatible. Il existe sans doute des hacks similaires pour d’autres marques mais je n’ai pas creusé la question.

Qu’est-ce qu’il permet de faire ce kit ? Voici quelques unes des possibilités.

  • Faire des photos en RAW (format sans perte)
  • Permettre des temps d’expositions beaucoup plus long ou court
  • Augmenter la taille des vidéos possible
  • Utiliser des scripts en Lua (pour prendre une photo toutes les x seconde par exemple)
  • Détection de mouvement
  • Indicateur de batterie plus précit
  • Quelques jeux ont même été implémentés

On peut paramétrer la gestion de la batterie assez finement

Pour l’installer, téléchargez d’abord la dernière version du logiciel souhaité. A ce jour la 1.0 est la version stable et 1.1 instable, à vous de voir si vous aimez vivre danregeusement. On le choix entre la version minimale ou complete (avec plein de scripts & co). Il existe deux méthodes pour configurer sa carte SD, la plus pratique est de rendre la carte SD bootable. Je vous conseille de lire la doc (la procédure varie en fonction du type de caméra et de taille de la carte) mais voici ce que j’ai fait :

  1. Télécharger le kit
  2. Formatez votre carte SD en FAT16 (paquet dosfstools)
  3. Copiez le contenu de l’archive téléchargée à la racine de la carte
  4. Démarrez la carte en mode lecture (pas pour prendre des photos donc)
  5. Entrez dans le menu, option « firmware update » et acceptez (le firmware ne sera pas réellement mit à jour)
  6. CDHK est chargé, appuyez une fois sur la touche raccourcit (un ALT apparait à l’écran) suivit de « menu »
  7. Dans le menu CHDK (plus fournis que celui d’origine hein), allez dans « Make Card Bootable »
  8. Sortez la carte SD de l’appareil et activez le lock sur la carte SD
  9. Redémarrez votre caméra

Vous pouvez désormais passer du menu normal au menu CHDK via la touche raccourcit (le ALT apparait sur l’écran). Vous pouvez maintenant explorer toutes les possibilités de votre nouveau jouet. Je vous renvoie vers le CHDK User Manual pour plus d’info ou vous amusez avec quelques scripts lua.

Navigateur de fichier, calendrier, jeux,…

Il manque plus que le serveur ssh pour être parfait mais avouez que pouvoir dire, « j’ai hacké mon appareil photo », ça a quand même plus de gueule que « j’ai jailbreaké mon iPhone ».

En cours d’écriture Kopi, de mon moteur de blog utilisant Django, je suis arrivé au stade des commentaires. Django propose déjà un module de commentaire assez pratique (avec honeypot, protection csrf…). En voulant rester dans la philosophie « less code is better » (particulièrement quand ça vient de moi), j’ai cherché à l’utiliser et l’étendre pour mes besoins. J’ai passé pas mal de temps à bidouiller et fouiller le code (pas toujours très clair la doc Django) et voulais donc partager mes trouvailles (et entendre vos critiques au cas où je suis complètement à coté de la plaque).

Un des points très important pour mon module de commentaire était de rester indépendant. Si un jour je créais une galerie de photo et que je voulais utiliser mon module sans rien devoir y changer. Il ne pouvait avoir AUCUNE référence à mon module de blog dans le module de commentaire. C’est le module de blog qui utilise le module de commentaire, pas l’inverse. Ce point n’est souvent pas respecté dans les exemples glanés sur le net et pourtant est tout à fait possible, ce grâce à la modularité de Django.

Un des problèmes que j’ai rencontré était la redirection des urls. Nativement, Django me redirige chaque post vers une url /posted/ avec un moche « Thank you for posting » digne d’un « It works » post-installation apache. Heureusement pour éviter cela, Django supporte dans son formulaire une balise <input name="next"/> dont la valeur est, comme on pourrait s’en douter, l’url de la page vers laquelle rediriger. Voici comment je m’y suis pris.

D’abord l’architecture de mon projet :

blog/
	templates/
		blog/
			post_detail.html
			...
comments/
	templates/
		comments/
			form.html
			...
	views.py
	urls.py
	...
kopi/
	settings.py
	urls.py
	...

Dans mon fichier kopi.urls.py, j’inclus de manière habituelle les urls concernant mon blog et mes commentaires, aucun lien entre les deux.

1
2
3
4
urlpatterns += patterns('',
        url(r'^comments/', include('comments.urls')),
        url(r'^', include('blog.urls')),
)

Du coté du blog, je gère donc mes articles. Une simple Generic View fait très bien ça en 5 lignes. Dans ma template blog/templates/blog/post_detail.html, j’inclus ma template de cette façon :

1
2
{% load comments %}
{% render_comment_form for current_post %}

où current_post est le nom de ma variable contenant mon article de blog.

Et voila pour le coté, blog, le reste est du coté des commentaires. Pour le module de base, je suis parti de ce qui a été fait dans django-basic-apps, l’import des méthodes de django.contrib.comments pour que mon module comments fasse exactement la même chose que celui dans les contrib sans avoir à l’importer dans les settings (c’est même conseillé, django est assez chiant quand deux apps portent le même nom). Le fichier comments/urls.py sera par exemple :

1
2
3
4
5
6
7
8
9
10
11
from django.conf.urls.defaults import *
from django.contrib.comments.urls import urlpatterns

urlpatterns = patterns('comments.views',
    # let's overwrite django.contrib.comments
    url(r'^post/$',
        view='custom_comment_post',
        name='comments-post-comment'),

    url( r'^', include( 'django.contrib.comments.urls' ) ),
)

Je reprend donc toutes les urls de django.contrib.comments.urls mais en forçant à utiliser ma view custom_comment_post plutôt que celle de base (Django cherche un match dans l’ordre et s’arrête au premier rencontré). Si vous voulez étendre le modèle pour y ajouter des champs, la logique est la même (Customizing the comments framework).

D’abord, je voulais réécrire ma template de formulaire pour qu’il connaisse la valeur next. J’ai donc créé le fichier comments/templates/comments/form.html avec (version simplifiée)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% load comments i18n %}

<form action="{% comment_form_target %}" method="post">{% csrf_token %}
  <div>{% if next %}
          <input type="hidden" name="next" value="{{ next }}" />
       {% else %}
          <input type="hidden" name="next" value="{{ form.target_object.get_absolute_url }}" /></div>
       {% endif %}
  </div>
  {% for field in form %}
      <p>{{ field.label_tag }} {{ field }}</p>
    {% endif %}
  {% endfor %}
  <p class="submit">
    <input type="submit" name="post" class="submit-post" value="{% trans "Post" %}" />
  </p>
</form>

Ainsi soit l’on passe une valeur choisie avec la variable next, soit on est redirigé vers l’url de l’objet pour lequel on affiche le formulaire. En mettant le for current_post dans le render_comment_form, j’indique ainsi que current_post sera le target_object. Et ça c’est très cool parce que ça veut dire que pour ma galerie d’image, je n’aurai qu’à faire {% render_comment_form for current_image %} et ne pas changer ma template form.html.

Après un test qu’est ce qu’on voit ? Le formulaire présent sur /monarticle/ fait une requête POST vers /post/, réponse depuis /posted/ (la page moche) mais ne reste pas dessus car a un header avec le code 302, redirection vers /monarticle/?c=42 où 42 est l’ID du commentaire.

Parfait ? Non pas encore complètement, j’aimerais que le visiteur aie une ancre qui l’amène au niveau de son commentaire. Je n’ai pas besoin de ce vieux ?c=42, par contre un #c42, ça m’intéresserait déjà un peu plus… Justement, c’est là qu’intervient mon overwrite au dessus avec la view custom_comment_post. On va forcer à récupérer l’url du commentaire plutôt que l’url du post un peu modifiée.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def custom_comment_post(request, next=None, using=None):
    # on utilise encore le code de la classe contrib
    response = contrib_comments.post_comment(request, next, using)

    if type(response) == HttpResponseRedirect:
        # url in the form /redirect_path/?c=comment_id
        redirect_path, comment_id  = response.get('Location').split( '?c=' )
        if comment_id:
            # get the related comment
            comment = Comment.objects.get( id=comment_id )
            if comment:
                # url in the form /comments/cr/object_id/comment_id#ccomment_id
                return HttpResponseRedirect( comment.get_absolute_url() )

    return response

Et là on laisse la magie de Django travailler, la fonction get_absolute_url du module de commentaire de base est bien foutu et va résoudre l’url /monarticle/#c42. Il vous suffit alors dans votre template d’ajouter une ancre pour ce format.

1
2
3
4
5
6
{% for comm in comment_list %}
  <article id="c{{comm.id}}">
    <a href="{{ comm.user_url }}">{{ comm.user_name }}</a> says:<br/>
    <p>{{ comm.comment }}</p>
  </article>
{% endfor %}

Vous n’aimez pas le format #c{{id}} ? Vous savez que vous êtes compliqué ? Mais ça tombe bien, Django a prévu ça. La fonction comment.get_absolute_url() prend un paramètre optionnel anchor_pattern="#c%(id)s". Il suffira d’appeler la fonction avec par exemple "#commentaire-id-%(id)s" pour obtenir quelque chose de plus agréable.

J’anticipe la question : que faire si je veux que sur mon application de blog j’ai #commentaire-post-%(id)s et sur ma galerie #commentaire-photo-%(id)s. Et bien là j’avoue que je n’ai pas encore trouvé de moyen simple de le faire. On peut y arriver en écrivant un nouveau templatetag (un overwrite de render_comment_form par exemple) mais franchement, ça fait beaucoup de boulot pour pas grand chose. Si vous avez une suggestion simple et élégante, je suis preneur.

Bear