1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  package com.levelonelabs.aimbot.modules;
34  
35  import java.text.SimpleDateFormat;
36  import java.util.ArrayList;
37  import java.util.Calendar;
38  import java.util.Date;
39  import java.util.HashMap;
40  import java.util.Iterator;
41  import java.util.StringTokenizer;
42  import java.util.Timer;
43  import java.util.TimerTask;
44  import java.util.logging.Logger;
45  
46  import org.w3c.dom.CDATASection;
47  import org.w3c.dom.Document;
48  import org.w3c.dom.Element;
49  
50  import com.levelonelabs.aim.AIMBuddy;
51  import com.levelonelabs.aim.XMLizable;
52  import com.levelonelabs.aimbot.AIMBot;
53  import com.levelonelabs.aimbot.BotModule;
54  
55  
56  /***
57   * A class to handle scheduling commands to happen at certain times
58   * 
59   * @author Steve Zingelewicz
60   * @created May 7th, 2003
61   */
62  public class ScheduleModule extends BotModule implements XMLizable {
63      private static ArrayList services;
64      private static Logger logger = Logger.getLogger(ScheduleModule.class.getName());
65      private static HashMap events = new HashMap();
66      private static Timer timer;
67  
68  
69      private class SchedulerTask extends TimerTask {
70          AIMBuddy buddy;
71          String cmd;
72          String triggerTime;
73          Date createDate;
74  
75  
76          SchedulerTask(AIMBuddy _buddy, String _cmd) {
77              buddy = _buddy;
78              cmd = _cmd;
79              createDate = new Date(); 
80                                          
81              
82          }
83  
84  
85          public void run() {
86              System.err.println("Timeout for: " + buddy.getName() + " cmd:" + cmd);
87              bot.handleMessage(buddy, cmd);
88  
89              removeEvent(this);
90          }
91  
92  
93          public AIMBuddy getBuddy() {
94              return (buddy);
95          }
96  
97  
98          public String getCommand() {
99              return (cmd);
100         }
101 
102 
103         public String getCreateDate() {
104             return (createDate.toString());
105         }
106     }
107 
108     /***
109      * Initialize the service commands.
110      */
111     static {
112         services = new ArrayList();
113         services.add("schedule");
114         services.add("cancel");
115         services.add("events");
116         
117         timer = new Timer();
118     }
119 
120 
121     /***
122      * Constructor for the ReminderModule object
123      * 
124      * @param bot
125      */
126     public ScheduleModule(AIMBot bot) {
127         super(bot);
128     }
129 
130 
131     /***
132      * Gets the name attribute of the SchedulerModule object
133      * 
134      * @return The name value
135      */
136     public String getName() {
137         return "Scheduler Module";
138     }
139 
140 
141     /***
142      * Gets the services attribute of the SchedulerModule object
143      * 
144      * @return The services value
145      */
146     public ArrayList getServices() {
147         return services;
148     }
149 
150 
151     /***
152      * Describes the usage of the module
153      * 
154      * @return the usage of the module
155      */
156     public String help() {
157         StringBuffer sb = new StringBuffer();
158         sb.append("<B>schedule <i>TEXT</i></B> (stores text in the system for retrieval later)\n");
159         sb.append("<B>cancel <i>All or #</i></B> (removes all items or a specific item)\n");
160         sb.append("<B>events</B> (lists all reminders)\n");
161         sb
162             .append("* If the preference \"reminderatsignon\" is set to true, you will automatically get a list when you login to aim.\n");
163 
164         return sb.toString();
165     }
166 
167 
168     /***
169      * Grabs and sends any stored reminders for a buddy
170      * 
171      * @param buddy
172      * @return whether any messages where found
173      */
174     public boolean retrieveEvents(AIMBuddy buddy) {
175         
176         ArrayList br = (ArrayList) events.get(buddy.getName());
177         if (br != null) {
178             String eventlist = "Events:<BR>";
179 
180             if (br.size() != 0) {
181                 
182                 for (int i = 0; i < br.size(); i++) {
183                     SchedulerTask st = (SchedulerTask) br.get(i);
184                     eventlist += ((i + 1) + ")" + (st.getCommand() + " scheduled " + st.getCreateDate() + "<BR>"));
185                 }
186             } else
187                 eventlist = "No events scheduled.";
188 
189             
190             super.sendMessage(buddy, eventlist);
191             return true;
192         }
193         return false;
194     }
195 
196 
197     /***
198      * Handle a messaging query
199      * 
200      * @param buddy
201      * @param query
202      */
203     public void performService(AIMBuddy buddy, String query) {
204         if (query.toLowerCase().startsWith("schedule")) {
205             handleSchedule(buddy, query);
206         } else if (query.toLowerCase().startsWith("cancel")) {
207             handleCancel(buddy, query);
208         } else if (query.toLowerCase().startsWith("events")) {
209             if (!retrieveEvents(buddy)) {
210                 sendMessage(buddy, "No events scheduled.");
211             }
212         }
213     }
214 
215 
216     /***
217      * Schedule time parsing function This function is getting huge and
218      * unwieldy. Once I get it all worked out, I'll figure out how to make it
219      * more manageable.
220      * 
221      * @param buddy
222      * @param query
223      */
224     private void handleSchedule(AIMBuddy buddy, String query) {
225         String token;
226         StringTokenizer st = new StringTokenizer(query, " ");
227         int state = 0;
228         int stop = 0;
229         char ch;
230         long period = 60000; 
231         String command = "";
232         SimpleDateFormat sdf = new SimpleDateFormat();
233         Date eventDate = null;
234         int sched_type = 0; 
235 
236         try {
237 
238             while (st.hasMoreTokens() && stop == 0) {
239                 token = st.nextToken();
240                 System.err.println("token: " + token + "state:" + String.valueOf(state));
241 
242                 switch (state) {
243                     case 0 :
244                         
245                         
246                         if (token.equals("schedule"))
247                             state = 1;
248                         else
249                             state = 99;
250                         break;
251                     case 1 :
252                         
253                         if (token.equals("at")) {
254                             sched_type = 1;
255                             state = 2;
256                         } else if (token.equals("in")) {
257                             sched_type = 2;
258                             state = 3;
259                         } else if (token.equals("every")) {
260                             sched_type = 3;
261                             state = 4;
262                         } else
263                             state = 99;
264                         break;
265                     case 2 :
266                         
267                         
268                         
269                         int at_idx = query.indexOf("at");
270                         int delim_idx = query.indexOf("-");
271                         if (at_idx != -1 && delim_idx != -1) {
272 
273                             System.err.println("Schedtoken:" + query.substring(at_idx + 2, delim_idx).trim());
274                             try {
275                                 eventDate = sdf.parse(query.substring(at_idx + 2, delim_idx).trim());
276                                 state = 51;
277                             } catch (Exception e) {
278                                 System.err.println("Can't parse date & time, trying just time..");
279                                 state = 99;
280                             }
281 
282                             try {
283                                 
284                                 sdf = new SimpleDateFormat("h:mm a");
285                                 eventDate = sdf.parse(query.substring(at_idx + 2, delim_idx).trim());
286                                 Calendar today = Calendar.getInstance();
287                                 today.set(Calendar.HOUR, 0);
288                                 today.set(Calendar.MINUTE, 0);
289                                 today.set(Calendar.SECOND, 0);
290                                 Date todaysDate = today.getTime();
291                                 System.err.println("event date:" + eventDate.toString());
292                                 System.err.println("today's date:" + todaysDate.toString());
293                                 System.err.println(eventDate.getTime());
294                                 System.err.println(todaysDate.getTime());
295                                 
296                                 
297                                 eventDate.setTime(eventDate.getTime() + todaysDate.getTime() - 18000000);
298                                 state = 51;
299                             } catch (Exception e) {
300                                 System.err.println("Can't parse date or time, bailing");
301                                 state = 99;
302                             }
303 
304                         } else
305                             state = 99;
306                         break;
307                     case 3 :
308                         
309                         
310                         
311                         
312                         ch = token.charAt(token.length() - 1);
313                         period = Long.parseLong(token.substring(0, token.length() - 1));
314                         state = 50;
315 
316                         if (ch == 's') { 
317                             period = period * 1000;
318                         } else if (ch == 'm') { 
319                             period = period * 60000;
320                         } else if (ch == 'h') { 
321                             period = period * 3600000;
322                         } else if (ch == 'd') { 
323                             period = period * 86400000;
324                         } else
325                             state = 99;
326                         break;
327                     case 4 :
328                         
329                         break;
330                     case 50 :
331                         
332                         if (token.equals("-")) {
333                             stop = 1;
334                             command = query.substring(query.indexOf('-') + 1).trim();
335                         } else
336                             state = 99;
337                         break;
338                     case 51 :
339                         
340                         if (token.equals("-")) {
341                             stop = 1;
342                             command = query.substring(query.indexOf('-') + 1).trim();
343                         }
344                         break;
345                     case 99 :
346                         
347                         stop = 1;
348                         break;
349                 }
350             }
351 
352             if (state == 1) 
353             
354             {
355                 if (!retrieveEvents(buddy)) {
356                     sendMessage(buddy, "No events available.");
357                 }
358             } else if (state == 50) { 
359                                         
360                 
361                 System.err.println("Scheduling " + command + " in " + String.valueOf(period));
362                 addEvent(buddy, period, command);
363                 sendMessage(buddy, "Event scheduled.");
364             } else if (state == 51) { 
365                                         
366                 
367                 System.err.println("Scheduling " + command + " at " + eventDate.toString());
368                 addEvent(buddy, eventDate, command);
369                 sendMessage(buddy, "Event scheduled.");
370             } else if (state == 99) {
371                 sendMessage(buddy, "Unable to understand schedule command");
372             } else
373                 sendMessage(buddy, "That schedule command is not implemented yet");
374         } catch (Exception e) {
375             sendMessage(buddy, "Unable to understand schedule command");
376             e.printStackTrace();
377         }
378     }
379 
380 
381     /***
382      * Forget functionality
383      * 
384      * @param buddy
385      * @param query
386      */
387     private void handleCancel(AIMBuddy buddy, String query) {
388         
389         StringTokenizer st = new StringTokenizer(query, " ");
390 
391         
392         if (st.countTokens() != 2) {
393             sendMessage(buddy, "ERROR:\n" + help());
394             return;
395         }
396         st.nextToken();
397         String tok = st.nextToken();
398         if (tok.equalsIgnoreCase("all")) {
399             clearEvents(buddy);
400             sendMessage(buddy, "All events removed.");
401         } else {
402             try {
403                 int loc = Integer.parseInt(tok) - 1;
404                 if (removeEvent(buddy, loc)) {
405                     sendMessage(buddy, "Event cancelled.");
406                 } else {
407                     sendMessage(buddy, "ERROR: number " + tok + " not valid.");
408                 }
409             } catch (Exception e) {
410                 e.printStackTrace();
411                 sendMessage(buddy, "ERROR: number invalid: " + tok);
412             }
413         }
414     }
415 
416 
417     /***
418      * Remove Specific Reminder
419      * 
420      * @param buddy
421      *            buddy
422      * @param i
423      *            list item number
424      * @return true if remove took place
425      */
426     public boolean removeEvent(AIMBuddy buddy, int i) {
427         ArrayList br = (ArrayList) events.get(buddy.getName());
428         if ((br != null) && (i >= 0) && (i < br.size())) {
429             br.remove(i);
430             return true;
431         }
432         return false;
433     }
434 
435 
436     /***
437      * @brief Removes an event given the event's SchedulerTask reference
438      * @param sTask
439      *            The reference to the item to remove
440      */
441     void removeEvent(SchedulerTask sTask) {
442         
443         ArrayList al;
444         al = (ArrayList) events.get(sTask.buddy.getName());
445         System.err.println("Removing events - " + String.valueOf(al.size()));
446         if (al != null) {
447             for (int i = 0; i < al.size(); i++) {
448 
449                 if ((SchedulerTask) al.get(i) == sTask) {
450                     al.remove(i);
451                     System.err.println("Removing " + String.valueOf(i));
452                     
453                     break;
454                 }
455             }
456         }
457     }
458 
459 
460     /***
461      * clear reminders for a buddy
462      * 
463      * @param buddy
464      *            buddy
465      */
466     public void clearEvents(AIMBuddy buddy) {
467         ArrayList br = (ArrayList) events.get(buddy.getName());
468         if (br != null) {
469             br.clear();
470         }
471     }
472 
473 
474     /***
475      * Add a reminder for a buddy
476      * 
477      * @param buddy
478      *            buddy
479      * @param period
480      *            Delay for timer
481      */
482     public void addEvent(AIMBuddy buddy, long period, String command) {
483         ArrayList br = (ArrayList) events.get(buddy.getName());
484         if (br == null) {
485             br = new ArrayList();
486             events.put(buddy.getName(), br);
487         }
488 
489         SchedulerTask st = new SchedulerTask(buddy, command);
490         timer.schedule(st, period);
491 
492         br.add(st);
493     }
494 
495 
496     /***
497      * Add a reminder for a buddy
498      * 
499      * @param buddy
500      *            buddy
501      * @param eventDate
502      *            Date of scheduled event
503      */
504     public void addEvent(AIMBuddy buddy, Date eventDate, String command) {
505         ArrayList br = (ArrayList) events.get(buddy.getName());
506         if (br == null) {
507             br = new ArrayList();
508             events.put(buddy.getName(), br);
509         }
510 
511         SchedulerTask st = new SchedulerTask(buddy, command);
512         timer.schedule(st, eventDate);
513 
514         br.add(st);
515     }
516 
517 
518     /***
519      * @see com.levelonelabs.aim.XMLizable#writeState(Element)
520      */
521     public void writeState(Element emptyStateElement) {
522         Document doc = emptyStateElement.getOwnerDocument();
523         Iterator iter = events.keySet().iterator();
524 
525         while (iter.hasNext()) {
526             String name = (String) iter.next();
527             ArrayList br = (ArrayList) events.get(name);
528             if (br.size() > 0) {
529                 Element buddyElem = doc.createElement("buddy");
530                 buddyElem.setAttribute("name", name);
531                 for (int i = 0; i < br.size(); i++) {
532                     Element remElem = doc.createElement("event");
533                     SchedulerTask st = (SchedulerTask) br.get(i);
534 
535                     Element buddy = doc.createElement("buddy");
536                     CDATASection buddy_data = doc.createCDATASection(st.getBuddy().getName());
537                     buddy.appendChild(buddy_data);
538 
539                     Element cmd = doc.createElement("command");
540                     CDATASection cmd_data = doc.createCDATASection(st.getCommand());
541                     cmd.appendChild(cmd_data);
542 
543                     Element createDate = doc.createElement("createDate");
544                     CDATASection cd_data = doc.createCDATASection(st.getCreateDate());
545                     createDate.appendChild(cd_data);
546 
547                     remElem.appendChild(buddy);
548                     remElem.appendChild(cmd);
549                     remElem.appendChild(createDate);
550                     buddyElem.appendChild(remElem);
551                 }
552                 emptyStateElement.appendChild(buddyElem);
553             }
554         }
555     }
556 
557 
558     /***
559      * @see com.levelonelabs.aim.XMLizable#readState(Element)
560      */
561 
562     
563     
564     
565     
566     
567     
568     
569     public void readState(Element fullStateElement) {
570         
571 
572 
573 
574 
575 
576 
577 
578 
579 
580 
581 
582 
583     }
584 }