0eb17bb78e3e03e8d4dbcd20bbb873cadc8cb87e
[gregoa/zavai.git] / src / at.vala
1 /*
2  * at - at interface
3  *
4  * Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 namespace at {
24
25 // Return the earliest ID in the queue, or -1 if none are found
26 // Queue is null for all queues, otherwise a queue name
27 public static int earliestID(string? queue = null)
28 {
29         string argv[4];
30         argv[0] = "/usr/bin/atq";
31         if (queue == null)
32                 argv[1] = null;
33         else
34         {
35                 argv[1] = "-q";
36                 argv[2] = queue;
37                 argv[3] = null;
38         }
39
40         Pid pid;
41         int stdout;
42
43         try
44         {
45                 if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdout, null))
46                         return -1;
47         } catch (SpawnError e) {
48                 stderr.printf("Cannot run 'at -q': %s\n", e.message);
49                 return -1;
50         }
51
52         FileStream fs = FileStream.fdopen(stdout, "r");
53         if (fs == null)
54                 return -1;
55
56         int first_id = -1;
57         time_t first_ts = 0;
58         char buf[200];
59         string? line;
60         while ((line = fs.gets(buf)) != null)
61         {
62                 if (!line[0].isdigit()) continue;
63                 weak string rest;
64                 ulong id = line.to_ulong(out rest, 10);
65                 Time t = Time();
66                 rest = t.strptime(rest.offset(1), "%a %b %d %H:%M:%S %Y");
67                 if (rest == null) continue;
68                 time_t tt = t.mktime();
69                 if (first_ts == 0 || tt < first_ts)
70                 {
71                         first_ts = tt;
72                         first_id = (int)id;
73                 }
74         }
75         Process.close_pid(pid);
76         return first_id;
77 }
78
79 public delegate bool jobParser(int fd);
80
81 // Get the contents of a job given its id
82 public static bool jobContents(int id, jobParser parser)
83 {
84         string argv[4];
85         argv[0] = "/usr/bin/at";
86         argv[1] = "-c";
87         argv[2] = id.to_string();
88         argv[3] = null;
89
90         Pid pid;
91         int stdoutfd;
92
93         try
94         {
95                 if (!Process.spawn_async_with_pipes("/", argv, null, SpawnFlags.STDERR_TO_DEV_NULL, null, out pid, null, out stdoutfd, null))
96                         return false;
97         } catch (SpawnError e) {
98                 stderr.printf("Cannot run 'at -c': %s\n", e.message);
99                 return false;
100         }
101
102         bool res = parser(stdoutfd);
103
104         Process.close_pid(pid);
105
106         return res;
107 }
108
109 /*
110 TODO: schedule alarms via at
111
112 Uses the 'z' queue.
113
114 atq -q z  can be used to list the jobs (for example, at startup, or after a job has run)
115 at -c id  can be used to query a job, parsing its contents (which can have
116           comments or variables being set)
117 zavai --notify ...  can be used to notify the job (and start zavai if it's not running)
118
119 Alarm needs to be able to serialize itself to an at invocation and to
120 deserialize itself from the output of at -c
121
122 Alarm needs to deserialize also a job with no special markers whatsoever: a
123 generic at job.
124 */
125
126
127 /*
128 public class Alarm : Object
129 {
130         // TODO: make a factory method to construct from an "at -c" output
131
132         // TODO: make a method that provides an at invocation
133
134         public signal void trigger(Alarm a);
135
136         public time_t deadline;
137         public string label;
138
139         public Alarm(time_t deadline, string label)
140         {
141                 this.deadline = deadline;
142                 this.label = label;
143         }
144 }
145 */
146
147         // Schedule a task that notifies a string
148         // TODO public void schedule_label(const Alarm a);
149
150         // Return the next item in the queue due to be run
151         // TODO public Alarm? next_scheduled();
152
153 }