6465c0d54188b696aa0b3b7ef812d62dc4efa590
[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 *procfile;
57         char *commands[2];
58         char *scanline;
59 };
60
61 #define INTERFACES 2
62 static struct interface interfaces[] = {
63         {"/proc/acpi/ibm/light",        {"off","on"},   "status: %9s" },
64         {"/proc/acpi/asus/mled",        {"0","1"},      "%9s" },
65 };
66
67 static struct interface *interface = NULL;
68
69 struct blinky {
70         int     state;
71         int     time;
72 };
73
74 static struct blinky seq[4] = {
75         {TOGGLE,        150},
76         {TOGGLE,        125},
77         {TOGGLE,        150},
78         {TOGGLE,        0}
79 };
80
81 static guint
82 blink(struct blinky *seq) {
83         FILE *file;
84         char *new_state = NULL;
85         char old_state[10] = "";
86         int ret;
87
88         if (interface == NULL) return FALSE;
89
90         // purple_debug_info("pidgin-blinklight","blink called with parameter: %i\n", seq->state);
91         
92         if (seq->state == ON)  new_state=interface->commands[ON];
93         if (seq->state == OFF) new_state=interface->commands[OFF];
94         if (seq->state == TOGGLE) {
95                 // purple_debug_info("pidgin-blinklight","trying to toggle\n");
96                 file = fopen(interface->procfile,"r");
97                       if (file == NULL) { perror ("Trying to open procfile for reading"); return FALSE;};
98                 ret = fscanf(file,interface->scanline,old_state);
99                       if (ret == EOF)  { perror ("Trying to read from procfile"); return FALSE;};
100                 ret = fclose(file);
101                       if (ret != 0) { perror ("Trying to close PROCFILE"); return FALSE;};
102                 // purple_debug_info("pidgin-blinklight","done reading old state %s\n", old_state);
103
104                 if (strcmp(old_state,interface->commands[ON])  == 0) new_state=interface->commands[OFF];
105                 if (strcmp(old_state,interface->commands[OFF]) == 0) new_state=interface->commands[ON];
106         }
107         
108         if (new_state == NULL) {
109                 // purple_debug_info("pidgin-blinklight","No new state defined\n");
110                 return FALSE;
111         }
112         // purple_debug_info("pidgin-blinklight","setting new state: %s\n", new_state);
113
114         file = fopen(interface->procfile,"w");
115                 if (file == NULL) { perror ("Trying to open procfile for writing"); return FALSE;};
116         ret = fprintf(file,"%s",new_state);
117                 if (ret < 0)   { perror ("Trying to write to procfile"); return FALSE;};
118         ret = fclose(file);
119                 if (ret != 0) { perror ("Trying to close procfile"); return FALSE;};
120
121         // purple_debug_info("pidgin-blinklight","done setting new state: %s\n", new_state);
122         
123         if (seq->time) 
124                 purple_timeout_add(seq->time,(GSourceFunc)blink,seq+1);
125
126         return FALSE;
127 }
128
129         
130
131 static void
132 gt_blink(PurpleAccount *account, const gchar *sender,
133          const gchar *message, int flags, gpointer data)
134 {
135         if (purple_prefs_get_bool("/plugins/core/pidgin-blinklight/focus"))
136         {
137                 // Blink in any case
138                 blink(seq);
139         } else {
140                 // Only blink when not having focus
141                 PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, sender, account);
142                 if (! purple_conversation_has_focus(conv)) 
143                         blink(seq);
144         }
145 }
146
147 static PurplePluginPrefFrame *
148 get_plugin_pref_frame(PurplePlugin *plugin)
149 {
150         PurplePluginPrefFrame *frame;
151         PurplePluginPref *ppref;
152
153         frame = purple_plugin_pref_frame_new();
154
155         ppref = purple_plugin_pref_new_with_name_and_label(
156                 "/plugins/core/pidgin-blinklight/focus",
157                 _("Blink even when conversation has the _focus.")
158         );
159
160         purple_plugin_pref_frame_add(frame, ppref);
161        
162         return frame;
163 }
164
165 static PurplePluginUiInfo prefs_info = 
166 {
167         get_plugin_pref_frame
168 };
169
170 static gboolean
171 gt_load(PurplePlugin *plugin) {
172         int i;
173
174         // Make /proc file writable
175         if (!fork())
176                 execl("/usr/lib/pidgin-blinklight/blinklight-fixperm","blinklight-fixperm",NULL);
177         
178         // figure out which interface to use
179         for (i=0; i< INTERFACES; i++) {
180                 if (! access(interfaces[i].procfile, R_OK)) {
181                         // File exists and is readable (not checking writable because of possible race condition)
182                         purple_debug_info("pidgin-blinklight","chose file %s.\n", interfaces[i].procfile);
183                         interface = &interfaces[i];
184                 }
185                 
186         }
187         if (interface == NULL) 
188                 purple_debug_info("pidgin-blinklight","no suitable file found, deactivating plugin.");
189         else
190                 purple_signal_connect(
191                         purple_conversations_get_handle(),
192                         "received-im-msg",
193                         plugin,
194                         PURPLE_CALLBACK(gt_blink),
195                         NULL
196                 );
197
198         // purple_debug_info("pidgin-blinklight","pidgin-blinklight has loaded\n");
199         return TRUE;
200 }
201
202 static gboolean
203 gt_unload(PurplePlugin *plugin) {
204
205         // purple_debug_info("pidgin-blinklight","pidgin-blinklight has unloaded\n");
206         return TRUE;
207 }
208
209 static PurplePluginInfo gt_info = {
210         PURPLE_PLUGIN_MAGIC,                                                                    /* plugin magic         */
211         PURPLE_MAJOR_VERSION,                                                                   /* major purple version */
212         PURPLE_MINOR_VERSION,                                                                   /* minor purple version */
213         PURPLE_PLUGIN_STANDARD,                                                                 /* type                 */
214         NULL,                                                                                   /* ui requirement       */
215         0,                                                                                      /* flags                */
216         NULL,                                                                                   /* dependencies         */
217         PURPLE_PRIORITY_DEFAULT,                                                                        /* priority             */
218         "gtk-nomeata-blinklight",                                                               /* id                   */
219         NULL,                                                                                   /* name                 */
220         VERSION,                                                                                /* version              */
221         NULL,                                                                                   /* summary              */
222         NULL,                                                                                   /* description          */
223
224         "Joachim Breitner <mail@joachim-breitner.de>",                                          /* author               */
225         "http://www.joachim-breitner.der/blog/",                                                                                /* homepage             */
226
227         gt_load,                                                                                /* load                 */
228         gt_unload,                                                                              /* unload               */
229         NULL,                                                                                   /* destroy              */
230
231         NULL,                                                                                   /* ui info              */
232         NULL,                                                                                   /* extra info           */
233         &prefs_info,                                                                            /* plugin prefs         */
234         NULL                                                                                    /* plugin actions       */
235 };
236
237 static void
238 init_plugin(PurplePlugin *plugin) {
239
240         purple_prefs_add_none("/plugins/core/pidgin-blinklight");
241         purple_prefs_add_bool("/plugins/core/pidgin-blinklight/focus", TRUE);
242
243 #ifdef ENABLE_NLS
244         bindtextdomain(PACKAGE, LOCALEDIR);
245         bind_textdomain_codeset(PACKAGE, "UTF-8");
246 #endif
247
248         gt_info.name            = _("Pidgin-Thinklight");
249         gt_info.summary         = _("Flickering Messages");
250         gt_info.description     = _(    "Pidgin-Thinklight:\n"
251                                         "Flashes the ThinkLight upon new messages\n"
252                                         "To use this, you need to have the ibm-acpi kernel module loaded.");
253
254         // purple_debug_info("pidgin-blinklight","pidgin-blinklight has init'ed");
255 }
256
257 PURPLE_INIT_PLUGIN(Pidgin-Thinklight, init_plugin, gt_info)