new asus led file, by kip
[darcs-mirror-pidgin-blinklight.debian.git] / src / pidgin-blinklight.c
1 /* © 2005-2007 Joachim Breitner
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16  */
17 #ifdef HAVE_CONFIG_H
18 # include "../config.h"
19 #endif
20
21 #define PURPLE_PLUGINS
22
23 #include <unistd.h>
24
25 #ifdef ENABLE_NLS
26 #  include <locale.h>
27 #  include <libintl.h>
28 #  define _(x) dgettext(PACKAGE, x)
29 #  ifdef dgettext_noop
30 #    define N_(String) dgettext_noop (PACKAGE, String)
31 #  else
32 #    define N_(String) (String)
33 #  endif
34 #else
35 #  include <locale.h>
36 #  define N_(String) (String)
37 #  define _(x) (x)
38 #  define ngettext(Singular, Plural, Number) ((Number == 1) ? (Singular) : (Plural))
39 #endif
40
41
42
43 #include <debug.h>
44 // #include <pidgin.h>
45 #include <plugin.h>
46 #include <conversation.h>
47 #include <version.h>
48 #include <eventloop.h>
49 #include <string.h>
50
51 #define OFF    0
52 #define ON     1
53 #define TOGGLE 2
54
55 struct interface {
56         char *sysfs;
57         char *commands[2];
58         char *scanline;
59 };
60
61 #define INTERFACES 3
62 static struct interface interfaces[] = {
63         {"/proc/acpi/ibm/light",                        {"off","on"},   "status: %9s" },
64         {"/proc/acpi/asus/mled",                        {"0","1"},          "%9s" },
65         {"/sys/class/leds/asus:phone/brightness",   {"0","1"},      "%9s" }
66 };
67
68 static struct interface *interface = NULL;
69
70 struct blinky {
71         int     state;
72         int     time;
73 };
74
75 /* TODO: We should really allow an option to continue blinking indefinitely
76          until user opens message */
77 static struct blinky seq[4] = {
78         {TOGGLE,        150},
79         {TOGGLE,        125},
80         {TOGGLE,        150},
81         {TOGGLE,        0}
82 };
83
84 static guint
85 blink(struct blinky *seq) {
86         FILE *file;
87         char *new_state = NULL;
88         char old_state[10] = "";
89         int ret;
90
91         if (interface == NULL) return FALSE;
92
93         // purple_debug_info("pidgin-blinklight","blink called with parameter: %i\n", seq->state);
94         
95         if (seq->state == ON)  new_state=interface->commands[ON];
96         if (seq->state == OFF) new_state=interface->commands[OFF];
97         if (seq->state == TOGGLE) {
98                 // purple_debug_info("pidgin-blinklight","trying to toggle\n");
99                 file = fopen(interface->sysfs,"r");
100                       if (file == NULL) { perror ("Trying to open sysfs for reading"); return FALSE;};
101                 ret = fscanf(file,interface->scanline,old_state);
102                       if (ret == EOF)  { perror ("Trying to read from sysfs"); return FALSE;};
103                 ret = fclose(file);
104                       if (ret != 0) { perror ("Trying to close sysfs"); return FALSE;};
105                 // purple_debug_info("pidgin-blinklight","done reading old state %s\n", old_state);
106
107                 if (strcmp(old_state,interface->commands[ON])  == 0) new_state=interface->commands[OFF];
108                 if (strcmp(old_state,interface->commands[OFF]) == 0) new_state=interface->commands[ON];
109         }
110         
111         if (new_state == NULL) {
112                 // purple_debug_info("pidgin-blinklight","No new state defined\n");
113                 return FALSE;
114         }
115         // purple_debug_info("pidgin-blinklight","setting new state: %s\n", new_state);
116
117         file = fopen(interface->sysfs,"w");
118                 if (file == NULL) { perror ("Trying to open sysfs for writing"); return FALSE;};
119         ret = fprintf(file,"%s",new_state);
120                 if (ret < 0)   { perror ("Trying to write to sysfs"); return FALSE;};
121         ret = fclose(file);
122                 if (ret != 0) { perror ("Trying to close sysfs"); return FALSE;};
123
124         // purple_debug_info("pidgin-blinklight","done setting new state: %s\n", new_state);
125         
126         if (seq->time) 
127                 purple_timeout_add(seq->time,(GSourceFunc)blink,seq+1);
128
129         return FALSE;
130 }
131
132         
133
134 static void
135 gt_blink(PurpleAccount *account, const gchar *sender,
136          const gchar *message, int flags, gpointer data)
137 {
138         if (purple_prefs_get_bool("/plugins/core/pidgin-blinklight/focus"))
139         {
140                 // Blink in any case
141                 blink(seq);
142         } else {
143                 // Only blink when not having focus
144                 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, sender, account);
145                 if (! purple_conversation_has_focus(conv)) 
146                         blink(seq);
147         }
148 }
149
150 static PurplePluginPrefFrame *
151 get_plugin_pref_frame(PurplePlugin *plugin)
152 {
153         PurplePluginPrefFrame *frame;
154         PurplePluginPref *ppref;
155
156         frame = purple_plugin_pref_frame_new();
157
158         ppref = purple_plugin_pref_new_with_name_and_label(
159                 "/plugins/core/pidgin-blinklight/focus",
160                 _("Blink even when conversation has the _focus.")
161         );
162
163         purple_plugin_pref_frame_add(frame, ppref);
164        
165         return frame;
166 }
167
168 static PurplePluginUiInfo prefs_info = 
169 {
170         get_plugin_pref_frame
171 };
172
173 static gboolean
174 gt_load(PurplePlugin *plugin) {
175         int i;
176
177         // Make /proc file writable
178         if (!fork())
179                 execl("/usr/lib/pidgin-blinklight/blinklight-fixperm","blinklight-fixperm",NULL);
180         
181         // figure out which interface to use
182         for (i=0; i< INTERFACES; i++) {
183                 if (! access(interfaces[i].sysfs, R_OK)) {
184                         // File exists and is readable (not checking writable because of possible race condition)
185                         purple_debug_info("pidgin-blinklight","chose file %s.\n", interfaces[i].sysfs);
186                         interface = &interfaces[i];
187                 }
188                 
189         }
190         if (interface == NULL) 
191                 purple_debug_info("pidgin-blinklight","no suitable file found, deactivating plugin.");
192         else
193                 purple_signal_connect(
194                         purple_conversations_get_handle(),
195                         "received-im-msg",
196                         plugin,
197                         PURPLE_CALLBACK(gt_blink),
198                         NULL
199                 );
200
201         // purple_debug_info("pidgin-blinklight","pidgin-blinklight has loaded\n");
202         return TRUE;
203 }
204
205 static gboolean
206 gt_unload(PurplePlugin *plugin) {
207
208         // purple_debug_info("pidgin-blinklight","pidgin-blinklight has unloaded\n");
209         return TRUE;
210 }
211
212 static PurplePluginInfo gt_info = {
213         PURPLE_PLUGIN_MAGIC,                                                                    /* plugin magic         */
214         PURPLE_MAJOR_VERSION,                                                                   /* major purple version */
215         PURPLE_MINOR_VERSION,                                                                   /* minor purple version */
216         PURPLE_PLUGIN_STANDARD,                                                                 /* type                 */
217         NULL,                                                                                   /* ui requirement       */
218         0,                                                                                      /* flags                */
219         NULL,                                                                                   /* dependencies         */
220         PURPLE_PRIORITY_DEFAULT,                                                                        /* priority             */
221         "gtk-nomeata-blinklight",                                                               /* id                   */
222         NULL,                                                                                   /* name                 */
223         VERSION,                                                                                /* version              */
224         NULL,                                                                                   /* summary              */
225         NULL,                                                                                   /* description          */
226
227         "Joachim Breitner <mail@joachim-breitner.de>",                                          /* author               */
228         "http://www.joachim-breitner.der/blog/",                                                                                /* homepage             */
229
230         gt_load,                                                                                /* load                 */
231         gt_unload,                                                                              /* unload               */
232         NULL,                                                                                   /* destroy              */
233
234         NULL,                                                                                   /* ui info              */
235         NULL,                                                                                   /* extra info           */
236         &prefs_info,                                                                            /* plugin prefs         */
237         NULL                                                                                    /* plugin actions       */
238 };
239
240 static void
241 init_plugin(PurplePlugin *plugin) {
242
243         purple_prefs_add_none("/plugins/core/pidgin-blinklight");
244         purple_prefs_add_bool("/plugins/core/pidgin-blinklight/focus", TRUE);
245
246 #ifdef ENABLE_NLS
247         bindtextdomain(PACKAGE, LOCALEDIR);
248         bind_textdomain_codeset(PACKAGE, "UTF-8");
249 #endif
250
251         gt_info.name            = _("Pidgin-Blinklight");
252         gt_info.summary         = _("Flickering Messages");
253         gt_info.description     = _(    "Pidgin-Blinklight:\n"
254                                         "Flashes the Blinklight upon new messages\n"
255                                         "To use this, you need to have the ibm-acpi or asus-laptop "
256                                         "kernel module loaded.");
257
258         // purple_debug_info("pidgin-blinklight","pidgin-blinklight has init'ed");
259 }
260
261 PURPLE_INIT_PLUGIN(Pidgin-Blinklight, init_plugin, gt_info)