usp10: Break with a better understanding on the handling of bidi strengths.
[wine] / dlls / mstask / task_trigger.c
1 /*
2  * Copyright (C) 2008 Google (Roy Shea)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include "winternl.h"
21 #include "mstask_private.h"
22 #include "wine/debug.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(mstask);
25
26 typedef struct
27 {
28     ITaskTrigger ITaskTrigger_iface;
29     LONG ref;
30     TASK_TRIGGER triggerCond;
31 } TaskTriggerImpl;
32
33 static inline TaskTriggerImpl *impl_from_ITaskTrigger(ITaskTrigger *iface)
34 {
35     return CONTAINING_RECORD(iface, TaskTriggerImpl, ITaskTrigger_iface);
36 }
37
38 static HRESULT WINAPI MSTASK_ITaskTrigger_QueryInterface(
39         ITaskTrigger* iface,
40         REFIID riid,
41         void **ppvObject)
42 {
43     TaskTriggerImpl *This = impl_from_ITaskTrigger(iface);
44
45     TRACE("IID: %s\n", debugstr_guid(riid));
46     if (ppvObject == NULL)
47         return E_POINTER;
48
49     if (IsEqualGUID(riid, &IID_IUnknown) ||
50             IsEqualGUID(riid, &IID_ITaskTrigger))
51     {
52         *ppvObject = &This->ITaskTrigger_iface;
53         ITaskTrigger_AddRef(iface);
54         return S_OK;
55     }
56
57     WARN("Unknown interface: %s\n", debugstr_guid(riid));
58     *ppvObject = NULL;
59     return E_NOINTERFACE;
60 }
61
62 static ULONG WINAPI MSTASK_ITaskTrigger_AddRef(
63         ITaskTrigger* iface)
64 {
65     TaskTriggerImpl *This = impl_from_ITaskTrigger(iface);
66     ULONG ref;
67     TRACE("\n");
68     ref = InterlockedIncrement(&This->ref);
69     return ref;
70 }
71
72 static ULONG WINAPI MSTASK_ITaskTrigger_Release(
73         ITaskTrigger* iface)
74 {
75     TaskTriggerImpl *This = impl_from_ITaskTrigger(iface);
76     ULONG ref;
77     TRACE("\n");
78     ref = InterlockedDecrement(&This->ref);
79     if (ref == 0)
80     {
81         HeapFree(GetProcessHeap(), 0, This);
82         InterlockedDecrement(&dll_ref);
83     }
84     return ref;
85 }
86
87 static HRESULT WINAPI MSTASK_ITaskTrigger_SetTrigger(
88         ITaskTrigger* iface,
89         const PTASK_TRIGGER pTrigger)
90 {
91     TaskTriggerImpl * This = impl_from_ITaskTrigger(iface);
92     TIME_FIELDS field_time;
93     LARGE_INTEGER sys_time;
94     TASK_TRIGGER tmp_trigger_cond;
95
96     TRACE("(%p, %p)\n", iface, pTrigger);
97
98     /* Verify valid structure size */
99     if (pTrigger->cbTriggerSize != sizeof(*pTrigger))
100         return E_INVALIDARG;
101     tmp_trigger_cond.cbTriggerSize = pTrigger->cbTriggerSize;
102
103     /* Reserved field must be zero */
104     tmp_trigger_cond.Reserved1 = 0;
105
106     /* Verify and set valid start date and time */
107     memset(&field_time, 0, sizeof(field_time));
108     field_time.Year = pTrigger->wBeginYear;
109     field_time.Month = pTrigger->wBeginMonth;
110     field_time.Day = pTrigger->wBeginDay;
111     field_time.Hour = pTrigger->wStartHour;
112     field_time.Minute = pTrigger->wStartMinute;
113     if (!RtlTimeFieldsToTime(&field_time, &sys_time))
114         return E_INVALIDARG;
115     tmp_trigger_cond.wBeginYear = pTrigger->wBeginYear;
116     tmp_trigger_cond.wBeginMonth = pTrigger->wBeginMonth;
117     tmp_trigger_cond.wBeginDay = pTrigger->wBeginDay;
118     tmp_trigger_cond.wStartHour = pTrigger->wStartHour;
119     tmp_trigger_cond.wStartMinute = pTrigger->wStartMinute;
120
121     /* Verify valid end date if TASK_TRIGGER_FLAG_HAS_END_DATE flag is set */
122     if (pTrigger->rgFlags & TASK_TRIGGER_FLAG_HAS_END_DATE)
123     {
124         memset(&field_time, 0, sizeof(field_time));
125         field_time.Year = pTrigger->wEndYear;
126         field_time.Month = pTrigger->wEndMonth;
127         field_time.Day = pTrigger->wEndDay;
128         if (!RtlTimeFieldsToTime(&field_time, &sys_time))
129             return E_INVALIDARG;
130     }
131
132     /* Set valid end date independent of TASK_TRIGGER_FLAG_HAS_END_DATE flag */
133     tmp_trigger_cond.wEndYear = pTrigger->wEndYear;
134     tmp_trigger_cond.wEndMonth = pTrigger->wEndMonth;
135     tmp_trigger_cond.wEndDay = pTrigger->wEndDay;
136
137     /* Verify duration and interval pair */
138     if (pTrigger->MinutesDuration <= pTrigger->MinutesInterval &&
139             pTrigger->MinutesInterval > 0)
140         return E_INVALIDARG;
141     if (pTrigger->MinutesDuration > 0 && pTrigger->MinutesInterval == 0)
142         return E_INVALIDARG;
143     tmp_trigger_cond.MinutesDuration = pTrigger->MinutesDuration;
144     tmp_trigger_cond.MinutesInterval = pTrigger->MinutesInterval;
145
146     /* Copy over flags */
147     tmp_trigger_cond.rgFlags = pTrigger->rgFlags;
148
149     /* Set TriggerType dependent fields of Type union */
150     tmp_trigger_cond.TriggerType = pTrigger->TriggerType;
151     switch (pTrigger->TriggerType)
152     {
153         case TASK_TIME_TRIGGER_DAILY:
154             tmp_trigger_cond.Type.Daily.DaysInterval =
155                     pTrigger->Type.Daily.DaysInterval;
156             break;
157         case TASK_TIME_TRIGGER_WEEKLY:
158             tmp_trigger_cond.Type.Weekly.WeeksInterval =
159                     pTrigger->Type.Weekly.WeeksInterval;
160             tmp_trigger_cond.Type.Weekly.rgfDaysOfTheWeek =
161                     pTrigger->Type.Weekly.rgfDaysOfTheWeek;
162             break;
163         case TASK_TIME_TRIGGER_MONTHLYDATE:
164             tmp_trigger_cond.Type.MonthlyDate.rgfDays =
165                     pTrigger->Type.MonthlyDate.rgfDays;
166             tmp_trigger_cond.Type.MonthlyDate.rgfMonths =
167                     pTrigger->Type.MonthlyDate.rgfMonths;
168             break;
169         case TASK_TIME_TRIGGER_MONTHLYDOW:
170             tmp_trigger_cond.Type.MonthlyDOW.wWhichWeek =
171                     pTrigger->Type.MonthlyDOW.wWhichWeek;
172             tmp_trigger_cond.Type.MonthlyDOW.rgfDaysOfTheWeek =
173                     pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek;
174             tmp_trigger_cond.Type.MonthlyDOW.rgfMonths =
175                     pTrigger->Type.MonthlyDOW.rgfMonths;
176             break;
177         case TASK_TIME_TRIGGER_ONCE:
178         case TASK_EVENT_TRIGGER_ON_IDLE:
179         case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
180         case TASK_EVENT_TRIGGER_AT_LOGON:
181         default:
182             tmp_trigger_cond.Type = This->triggerCond.Type;
183             break;
184     }
185
186     /* Reserved field must be zero */
187     tmp_trigger_cond.Reserved2 = 0;
188
189     /* wRandomMinutesInterval not currently used and is initialized to zero */
190     tmp_trigger_cond.wRandomMinutesInterval = 0;
191
192     /* Update object copy of triggerCond */
193     This->triggerCond = tmp_trigger_cond;
194
195     return S_OK;
196 }
197
198 static HRESULT WINAPI MSTASK_ITaskTrigger_GetTrigger(
199         ITaskTrigger* iface,
200         PTASK_TRIGGER pTrigger)
201 {
202     TaskTriggerImpl * This = impl_from_ITaskTrigger(iface);
203
204     TRACE("(%p, %p)\n", iface, pTrigger);
205
206     /* Native implementation doesn't verify equivalent cbTriggerSize fields */
207
208     /* Copy relevant fields of the structure */
209     pTrigger->cbTriggerSize = This->triggerCond.cbTriggerSize;
210     pTrigger->Reserved1 = 0;
211     pTrigger->wBeginYear = This->triggerCond.wBeginYear;
212     pTrigger->wBeginMonth = This->triggerCond.wBeginMonth;
213     pTrigger->wBeginDay = This->triggerCond.wBeginDay;
214     pTrigger->wEndYear = This->triggerCond.wEndYear;
215     pTrigger->wEndMonth = This->triggerCond.wEndMonth;
216     pTrigger->wEndDay = This->triggerCond.wEndDay;
217     pTrigger->wStartHour = This->triggerCond.wStartHour;
218     pTrigger->wStartMinute = This->triggerCond.wStartMinute;
219     pTrigger->MinutesDuration = This->triggerCond.MinutesDuration;
220     pTrigger->MinutesInterval = This->triggerCond.MinutesInterval;
221     pTrigger->rgFlags = This->triggerCond.rgFlags;
222     pTrigger->TriggerType = This->triggerCond.TriggerType;
223     switch (This->triggerCond.TriggerType)
224     {
225         case TASK_TIME_TRIGGER_DAILY:
226             pTrigger->Type.Daily.DaysInterval =
227                     This->triggerCond.Type.Daily.DaysInterval;
228             break;
229         case TASK_TIME_TRIGGER_WEEKLY:
230             pTrigger->Type.Weekly.WeeksInterval =
231                     This->triggerCond.Type.Weekly.WeeksInterval;
232             pTrigger->Type.Weekly.rgfDaysOfTheWeek =
233                     This->triggerCond.Type.Weekly.rgfDaysOfTheWeek;
234             break;
235         case TASK_TIME_TRIGGER_MONTHLYDATE:
236             pTrigger->Type.MonthlyDate.rgfDays =
237                     This->triggerCond.Type.MonthlyDate.rgfDays;
238             pTrigger->Type.MonthlyDate.rgfMonths =
239                     This->triggerCond.Type.MonthlyDate.rgfMonths;
240             break;
241         case TASK_TIME_TRIGGER_MONTHLYDOW:
242             pTrigger->Type.MonthlyDOW.wWhichWeek =
243                     This->triggerCond.Type.MonthlyDOW.wWhichWeek;
244             pTrigger->Type.MonthlyDOW.rgfDaysOfTheWeek =
245                     This->triggerCond.Type.MonthlyDOW.rgfDaysOfTheWeek;
246             pTrigger->Type.MonthlyDOW.rgfMonths =
247                     This->triggerCond.Type.MonthlyDOW.rgfMonths;
248             break;
249         case TASK_TIME_TRIGGER_ONCE:
250         case TASK_EVENT_TRIGGER_ON_IDLE:
251         case TASK_EVENT_TRIGGER_AT_SYSTEMSTART:
252         case TASK_EVENT_TRIGGER_AT_LOGON:
253         default:
254             break;
255     }
256     pTrigger->Reserved2 = 0;
257     pTrigger->wRandomMinutesInterval = 0;
258     return S_OK;
259 }
260
261 static HRESULT WINAPI MSTASK_ITaskTrigger_GetTriggerString(
262         ITaskTrigger* iface,
263         LPWSTR *ppwszTrigger)
264 {
265     FIXME("Not implemented\n");
266     return E_NOTIMPL;
267 }
268
269 static const ITaskTriggerVtbl MSTASK_ITaskTriggerVtbl =
270 {
271     MSTASK_ITaskTrigger_QueryInterface,
272     MSTASK_ITaskTrigger_AddRef,
273     MSTASK_ITaskTrigger_Release,
274     MSTASK_ITaskTrigger_SetTrigger,
275     MSTASK_ITaskTrigger_GetTrigger,
276     MSTASK_ITaskTrigger_GetTriggerString
277 };
278
279 HRESULT TaskTriggerConstructor(LPVOID *ppObj)
280 {
281     TaskTriggerImpl *This;
282     SYSTEMTIME time;
283     TRACE("(%p)\n", ppObj);
284
285     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
286     if (!This)
287         return E_OUTOFMEMORY;
288
289     This->ITaskTrigger_iface.lpVtbl = &MSTASK_ITaskTriggerVtbl;
290     This->ref = 1;
291
292     /* Most fields of triggerCond default to zero.  Initialize other
293      * fields to default values. */
294     memset(&This->triggerCond, 0, sizeof(TASK_TRIGGER));
295     GetLocalTime(&time);
296     This->triggerCond.cbTriggerSize = sizeof(This->triggerCond);
297     This->triggerCond.wBeginYear = time.wYear;
298     This->triggerCond.wBeginMonth = time.wMonth;
299     This->triggerCond.wBeginDay = time.wDay;
300     This->triggerCond.wStartHour = time.wHour;
301     This->triggerCond.wStartMinute = time.wMinute;
302     This->triggerCond.rgFlags = TASK_TRIGGER_FLAG_DISABLED;
303     This->triggerCond.TriggerType = TASK_TIME_TRIGGER_DAILY,
304     This->triggerCond.Type.Daily.DaysInterval = 1;
305
306     *ppObj = &This->ITaskTrigger_iface;
307     InterlockedIncrement(&dll_ref);
308     return S_OK;
309 }