5114f4166229c299a242df63e93933d091b52954
[platform/upstream/iotivity.git] / resource / csdk / stack / src / oicgroup.c
1 //******************************************************************
2 //
3 // Copyright 2014 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #define _POSIX_C_SOURCE 200112L
22
23 #include "iotivity_config.h"
24
25 #include <string.h>
26
27 #include "oicgroup.h"
28 #if defined (__TIZENRT__)
29 #include <apps/netutils/cJSON.h>
30 #else
31 #include "cJSON.h"
32 #endif
33 #include "cbor.h"
34 #include "ocpayload.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "occollection.h"
38 #include "logger.h"
39 #include "timer.h"
40
41 #define TAG "OIC_RI_GROUP"
42
43 #define DESC_DELIMITER          "\""
44 #define ACTION_DELIMITER        "*"
45 #define ATTR_DELIMITER          "|"
46 #define ATTR_ASSIGN             "="
47
48 // Definitions for operations related to actions
49 #define DO_ACTION               "DoAction"
50 #define GET_ACTIONSET           "GetActionSet"
51 #define ACTIONSET               "ActionSet"
52 #define CANCEL_ACTIONSET        "CancelAction"
53 #define DELETE_ACTIONSET        "DelActionSet"
54
55 #define DEFAULT_CONTEXT_VALUE 0x99
56
57 #define VARIFY_POINTER_NULL(pointer, result, toExit) \
58     if(pointer == NULL) \
59     {\
60         result = OC_STACK_NO_MEMORY;\
61         goto toExit;\
62     }
63 #define VARIFY_PARAM_NULL(pointer, result, toExit) \
64     if(pointer == NULL)\
65     {\
66         result = OC_STACK_INVALID_PARAM;\
67         goto exit;\
68     }
69
70 #define OCFREE(pointer) \
71     { \
72         OICFree(pointer); \
73         pointer = NULL; \
74     }
75
76 // Mutex implementation macros
77 #if defined(HAVE_PTHREAD_H)
78
79  #include <pthread.h>
80  pthread_mutex_t g_scheduledResourceLock;
81  #define MUTEX_LOCK(ARG_NAME)       { pthread_mutex_lock(ARG_NAME); }
82  #define MUTEX_UNLOCK(ARG_NAME)     { pthread_mutex_unlock(ARG_NAME); }
83  #define MUTEX_INITIALIZE(ARG_NAME) { }
84  #define MUTEX_TERMINATE(ARG_NAME)  { }
85
86 #elif defined(HAVE_WINDOWS_H)
87
88  #include <windows.h>
89  CRITICAL_SECTION g_scheduledResourceLock;
90  bool g_initializedScheduledResourceLock = false;
91  #define MUTEX_LOCK(ARG_NAME)       { EnterCriticalSection(ARG_NAME); }
92  #define MUTEX_UNLOCK(ARG_NAME)     { LeaveCriticalSection(ARG_NAME); }
93  #define MUTEX_INITIALIZE(ARG_NAME) { assert(!g_initializedScheduledResourceLock); \
94                                       InitializeCriticalSection(ARG_NAME); \
95                                       g_initializedScheduledResourceLock = true; \
96                                     }
97  #define MUTEX_TERMINATE(ARG_NAME)  { if (g_initializedScheduledResourceLock) \
98                                       { \
99                                           DeleteCriticalSection(ARG_NAME); \
100                                           g_initializedScheduledResourceLock = false; \
101                                       } \
102                                     }
103
104 #elif defined(WITH_ARDUINO)
105
106  #define MUTEX_LOCK(ARG_NAME)       { }
107  #define MUTEX_UNLOCK(ARG_NAME)     { }
108  #define MUTEX_INITIALIZE(ARG_NAME) { }
109  #define MUTEX_TERMINATE(ARG_NAME)  { }
110
111 #else
112
113  ERROR Need mutex implementation on this platform
114
115 #endif
116
117 enum ACTION_TYPE
118 {
119     NONE = 0, SCHEDULED, RECURSIVE
120 };
121
122 typedef struct scheduledresourceinfo
123 {
124     OCResource *resource;
125     OCActionSet *actionset;
126
127     int timer_id;
128
129     OCServerRequest *ehRequest;
130
131     time_t time;
132     struct scheduledresourceinfo* next;
133 } ScheduledResourceInfo;
134
135 ScheduledResourceInfo *g_scheduleResourceList = NULL;
136
137 void AddScheduledResource(ScheduledResourceInfo **head,
138         ScheduledResourceInfo* add)
139 {
140     OIC_LOG(INFO, TAG, "AddScheduledResource Entering...");
141
142     MUTEX_LOCK(&g_scheduledResourceLock);
143     ScheduledResourceInfo *tmp = NULL;
144
145     if (*head != NULL)
146     {
147         tmp = *head;
148
149         while (tmp->next)
150         {
151             tmp = tmp->next;
152         }
153         tmp->next = add;
154     }
155     else
156     {
157         *head = add;
158     }
159     MUTEX_UNLOCK(&g_scheduledResourceLock);
160 }
161
162 ScheduledResourceInfo* GetScheduledResource(ScheduledResourceInfo *head)
163 {
164     OIC_LOG(INFO, TAG, "GetScheduledResource Entering...");
165
166     MUTEX_LOCK(&g_scheduledResourceLock);
167
168     time_t t_now;
169
170     ScheduledResourceInfo *tmp = NULL;
171     tmp = head;
172
173 #if !defined(WITH_ARDUINO)
174     time(&t_now);
175 #else
176     t_now = now();
177 #endif
178
179     if (tmp)
180     {
181         while (tmp)
182         {
183             time_t diffTm = 0;
184             diffTm = timespec_diff(tmp->time, t_now);
185
186             if (diffTm <= (time_t) 0)
187             {
188                 OIC_LOG(INFO, TAG, "return Call INFO.");
189                 goto exit;
190             }
191
192             tmp = tmp->next;
193         }
194     }
195
196     exit:
197
198     MUTEX_UNLOCK(&g_scheduledResourceLock);
199
200     if (tmp == NULL)
201     {
202         OIC_LOG(INFO, TAG, "Cannot Find Call Info.");
203     }
204     return tmp;
205 }
206
207 ScheduledResourceInfo* GetScheduledResourceByActionSetName(ScheduledResourceInfo *head, char *setName)
208 {
209     OIC_LOG(INFO, TAG, "GetScheduledResourceByActionSetName Entering...");
210
211     MUTEX_LOCK(&g_scheduledResourceLock);
212
213     ScheduledResourceInfo *tmp = NULL;
214     tmp = head;
215
216     if (tmp)
217     {
218         while (tmp)
219         {
220             if (strcmp(tmp->actionset->actionsetName, setName) == 0)
221             {
222                 OIC_LOG(INFO, TAG, "return Call INFO.");
223                 goto exit;
224             }
225             tmp = tmp->next;
226         }
227     }
228
229 exit:
230
231     MUTEX_UNLOCK(&g_scheduledResourceLock);
232
233     if (tmp == NULL)
234     {
235         OIC_LOG(INFO, TAG, "Cannot Find Call Info.");
236     }
237     return tmp;
238 }
239
240 void RemoveScheduledResource(ScheduledResourceInfo **head,
241         ScheduledResourceInfo* del)
242 {
243
244     MUTEX_LOCK(&g_scheduledResourceLock);
245
246     OIC_LOG(INFO, TAG, "RemoveScheduledResource Entering...");
247     ScheduledResourceInfo *tmp = NULL;
248
249     if (del == NULL)
250     {
251
252         MUTEX_UNLOCK(&g_scheduledResourceLock);
253
254         return;
255     }
256
257     if (*head == del)
258     {
259         *head = (*head)->next;
260     }
261     else
262     {
263         tmp = *head;
264         while (tmp->next && (tmp->next != del))
265         {
266             tmp = tmp->next;
267         }
268         if (tmp->next)
269         {
270             tmp->next = del->next;
271         }
272     }
273
274     OCFREE(del)
275
276     MUTEX_UNLOCK(&g_scheduledResourceLock);
277 }
278
279 typedef struct aggregatehandleinfo
280 {
281     OCServerRequest *ehRequest;
282     OCDoHandle required;
283     OCResource *collResource;
284
285     struct aggregatehandleinfo *next;
286 } ClientRequestInfo;
287
288 ClientRequestInfo *clientRequstList = NULL;
289
290 void AddClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* add)
291 {
292     ClientRequestInfo *tmp = NULL;
293
294     if (*head != NULL)
295     {
296         tmp = *head;
297
298         while (tmp->next)
299         {
300             tmp = tmp->next;
301         }
302         tmp->next = add;
303     }
304     else
305     {
306         *head = add;
307     }
308 }
309
310 ClientRequestInfo* GetClientRequestInfo(ClientRequestInfo *head,
311         OCDoHandle handle)
312 {
313     ClientRequestInfo *tmp = NULL;
314
315     tmp = head;
316
317     if (tmp)
318     {
319         while (tmp)
320         {
321             if (tmp->required == handle)
322             {
323                 break;
324             }
325
326             tmp = tmp->next;
327         }
328
329         return tmp;
330     }
331     return NULL;
332 }
333
334 void RemoveClientRequestInfo(ClientRequestInfo **head, ClientRequestInfo* del)
335 {
336     ClientRequestInfo *tmp = NULL;
337
338     if (del == NULL)
339         return;
340
341     if (*head == del)
342     {
343         *head = (*head)->next;
344     }
345     else
346     {
347         tmp = *head;
348         while (tmp->next && (tmp->next != del))
349         {
350             tmp = tmp->next;
351         }
352         if (tmp->next)
353         {
354             tmp->next = del->next;
355         }
356     }
357 }
358
359 void AddCapability(OCCapability** head, OCCapability* node)
360 {
361     OCCapability *pointer = *head;
362     if (NULL == pointer)
363     {
364         *head = node;
365     }
366     else
367     {
368         while (pointer->next != NULL)
369         {
370             pointer = pointer->next;
371         }
372
373         pointer->next = node;
374     }
375 }
376
377 void AddAction(OCAction** head, OCAction* node)
378 {
379     OCAction *pointer = *head;
380     if (NULL == pointer)
381     {
382         *head = node;
383     }
384     else
385     {
386
387         while (pointer->next != NULL)
388         {
389             pointer = pointer->next;
390         }
391
392         pointer->next = node;
393     }
394 }
395
396 OCStackResult AddActionSet(OCActionSet **head, OCActionSet* node)
397 {
398     OCActionSet *pointer = *head;
399     OCActionSet *prev = NULL;
400     if(node == NULL)
401     {
402         return OC_STACK_ERROR;
403     }
404     if (NULL == pointer)
405     {
406         *head = node;
407     }
408     else
409     {
410         prev = pointer;
411         while (pointer != NULL)
412         {
413             // check the uniqeness of actionsetname.
414             if (strcmp(pointer->actionsetName, node->actionsetName) == 0)
415             {
416                 return OC_STACK_ERROR;
417             }
418
419             prev = pointer;
420             pointer = pointer->next;
421         }
422
423         prev->next = node;
424     }
425
426     return OC_STACK_OK;
427 }
428
429 void DeleteCapability(OCCapability *del)
430 {
431     OCFREE(del->capability)
432     del->capability = NULL;
433     OCFREE(del->status)
434     del->status = NULL;
435     OCFREE(del)
436 }
437
438 void DeleteAction(OCAction** action)
439 {
440     OCCapability* pointer = (*action)->head;
441     OCCapability* pDel = NULL;
442
443     while (pointer)
444     {
445         pDel = pointer;
446         pointer = pointer->next;
447
448         DeleteCapability(pDel);
449     }
450     OCFREE((*action)->resourceUri)
451     (*action)->next = NULL;
452     OCFREE(*action)
453 }
454
455 void DeleteActionSet(OCActionSet** actionset)
456 {
457     OCAction* pointer = NULL;
458     OCAction* pDel = NULL;
459
460     if(*actionset == NULL)
461         return;
462
463     pointer = (*actionset)->head;
464
465     while (pointer)
466     {
467         pDel = pointer;
468         pointer = pointer->next;
469
470         DeleteAction(&pDel);
471     }
472     //    (*actionset)->head = NULL;
473     OCFREE((*actionset)->actionsetName)
474     OCFREE(*actionset)
475 }
476
477 OCStackResult FindAndDeleteActionSet(OCResource **resource,
478         const char * actionsetName)
479 {
480     if (*resource != NULL)
481     {
482         OCActionSet *pointer = NULL;
483         OCActionSet *pDel = NULL;
484
485         pointer = (*resource)->actionsetHead;
486
487         if (pointer == NULL)
488         {
489             return OC_STACK_ERROR;
490         }
491         else
492         {
493             if (strcmp(pointer->actionsetName, actionsetName) == 0)
494             {
495                 if (pointer->next != NULL)
496                     (*resource)->actionsetHead = pointer->next;
497                 else
498                     (*resource)->actionsetHead = NULL;
499
500                 DeleteActionSet(&pointer);
501             }
502             else if (pointer->next != NULL)
503             {
504                 while (pointer)
505                 {
506                     if (pointer->next != NULL)
507                     {
508                         if (strcmp(pointer->next->actionsetName, actionsetName)
509                                 == 0)
510                         {
511                             pDel = pointer->next;
512                             pointer->next = pointer->next->next;
513
514                             DeleteActionSet(&pDel);
515                         }
516                     }
517                     pointer = pointer->next;
518                 }
519             }
520
521             return OC_STACK_OK;
522         }
523
524     }
525     return OC_STACK_ERROR;
526 }
527
528 OCStackResult GetActionSet(const char *actionName, OCActionSet *head,
529         OCActionSet** actionset)
530 {
531     OCActionSet *pointer = head;
532
533     while (pointer)
534     {
535         if (strcmp(pointer->actionsetName, actionName) == 0)
536         {
537             *actionset = pointer;
538             return OC_STACK_OK;
539         }
540
541         pointer = pointer->next;
542     }
543
544     return OC_STACK_ERROR;
545
546 }
547
548 OCStackResult ExtractKeyValueFromRequest(OCEntityHandlerRequest *ehRequest,
549                                         char **key, char **value)
550 {
551     OCStackResult result = OC_STACK_OK;
552
553     char *actionSetStr = NULL;
554
555     if( NULL == ehRequest->payload )
556     {
557         result = OC_STACK_ERROR;
558         goto exit;
559     }
560
561     OCRepPayload* input;
562
563     input = (OCRepPayload*)(ehRequest->payload);
564
565     if(OCRepPayloadGetPropString(input, ACTIONSET, &actionSetStr))
566     {
567         *key = OICStrdup(ACTIONSET);
568         VARIFY_POINTER_NULL(*key, result, exit);
569
570         *value = OICStrdup(actionSetStr);
571         VARIFY_POINTER_NULL(*value, result, exit);
572     }
573     else if(OCRepPayloadGetPropString(input, DO_ACTION, &actionSetStr))
574     {
575         *key = OICStrdup(DO_ACTION);
576         VARIFY_POINTER_NULL(*key, result, exit);
577
578         *value = OICStrdup(actionSetStr);
579         VARIFY_POINTER_NULL(*value, result, exit);
580     }
581     else if(OCRepPayloadGetPropString(input, GET_ACTIONSET, &actionSetStr))
582     {
583         *key = OICStrdup(GET_ACTIONSET);
584         VARIFY_POINTER_NULL(*key, result, exit);
585
586         *value = OICStrdup(actionSetStr);
587         VARIFY_POINTER_NULL(*value, result, exit);
588     }
589     else if(OCRepPayloadGetPropString(input, DELETE_ACTIONSET, &actionSetStr))
590     {
591         *key = OICStrdup(DELETE_ACTIONSET);
592         VARIFY_POINTER_NULL(*key, result, exit);
593
594         *value = OICStrdup(actionSetStr);
595         VARIFY_POINTER_NULL(*value, result, exit);
596     }
597     else if(OCRepPayloadGetPropString(input, CANCEL_ACTIONSET, &actionSetStr))
598     {
599         *key = OICStrdup(CANCEL_ACTIONSET);
600         VARIFY_POINTER_NULL(*key, result, exit);
601
602         *value = OICStrdup(actionSetStr);
603         VARIFY_POINTER_NULL(*value, result, exit);
604     }
605     else
606     {
607         result = OC_STACK_ERROR;
608     }
609
610 exit:
611     if (result != OC_STACK_OK)
612     {
613         OCFREE(*key)
614         OCFREE(*value)
615     }
616
617     OCFREE(actionSetStr);
618
619     return result;
620 }
621
622 OCStackResult ExtractActionSetNameAndDelaytime(char *pChar, char **setName,
623         long int *pa)
624 {
625     char *token = NULL, *tokenPtr = NULL;
626     OCStackResult result = OC_STACK_OK;
627
628     token = (char*) strtok_r(pChar, ACTION_DELIMITER, &tokenPtr);
629     VARIFY_POINTER_NULL(token, result, exit)
630
631     *setName = (char *) OICMalloc(strlen(token) + 1);
632     VARIFY_POINTER_NULL(*setName, result, exit)
633     VARIFY_PARAM_NULL(token, result, exit)
634     strncpy(*setName, token, strlen(token) + 1);
635
636     token = strtok_r(NULL, ACTION_DELIMITER, &tokenPtr);
637     VARIFY_POINTER_NULL(pa, result, exit)
638     VARIFY_PARAM_NULL(token, result, exit)
639     *pa = atoi(token);
640
641     return OC_STACK_OK;
642
643 exit:
644     OCFREE(*setName);
645     return result;
646 }
647
648 OCStackResult BuildActionSetFromString(OCActionSet **set, char* actiondesc)
649 {
650     OCStackResult result = OC_STACK_OK;
651
652     char *iterToken = NULL, *iterTokenPtr = NULL;
653     char *descIterToken = NULL, *descIterTokenPtr = NULL;
654     char *attrIterToken = NULL, *attrIterTokenPtr = NULL;
655     char *desc = NULL, *attr = NULL;
656     char *key = NULL, *value = NULL;
657
658     OCAction *action = NULL;
659     OCCapability *capa = NULL;
660
661     OIC_LOG(INFO, TAG, "Build ActionSet Instance.");
662
663     *set = (OCActionSet*) OICMalloc(sizeof(OCActionSet));
664     VARIFY_POINTER_NULL(*set, result, exit)
665
666     iterToken = (char *) strtok_r(actiondesc, ACTION_DELIMITER, &iterTokenPtr);
667     VARIFY_POINTER_NULL(iterToken, result, exit);
668
669     // ActionSet Name
670     memset(*set, 0, sizeof(OCActionSet));
671     (*set)->actionsetName = (char *) OICMalloc(strlen(iterToken) + 1);
672     VARIFY_POINTER_NULL((*set)->actionsetName, result, exit)
673     VARIFY_PARAM_NULL(iterToken, result, exit)
674     strncpy((*set)->actionsetName, iterToken, strlen(iterToken) + 1);
675
676     // Time info. for Scheduled/Recursive Group action.
677     // d is meant Day of the week.
678     // T is meant ActionType.
679     // yyyy-mm-dd hh:mm:ss d
680     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
681     VARIFY_PARAM_NULL(iterToken, result, exit)
682 #if !defined(WITH_ARDUINO)
683     if( 2 != sscanf(iterToken, "%ld %u", &(*set)->timesteps, &(*set)->type) )
684     {
685         // If the return value should be 2, the number of items in the argument. Otherwise, it fails.
686         goto exit;
687     }
688 #endif
689
690     OIC_LOG_V(INFO, TAG, "ActionSet Name : %s", (*set)->actionsetName);
691
692     iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
693     while (iterToken)
694     {
695         desc = (char *) OICMalloc(strlen(iterToken) + 1);
696         VARIFY_POINTER_NULL(desc, result, exit)
697         VARIFY_PARAM_NULL(desc, result, exit)
698         strncpy(desc, iterToken, strlen(iterToken) + 1);
699         descIterToken = (char *) strtok_r(desc, ATTR_DELIMITER,
700                 &descIterTokenPtr);
701         while (descIterToken)
702         {
703             attr = (char *) OICMalloc(strlen(descIterToken) + 1);
704             VARIFY_POINTER_NULL(attr, result, exit)
705             VARIFY_PARAM_NULL(descIterToken, result, exit)
706             strncpy(attr, descIterToken, strlen(descIterToken) + 1);
707
708             attrIterToken = (char *) strtok_r(attr, ATTR_ASSIGN,
709                     &attrIterTokenPtr);
710             VARIFY_POINTER_NULL(attrIterToken, result, exit);
711
712             key = (char *) OICMalloc(strlen(attrIterToken) + 1);
713             VARIFY_POINTER_NULL(key, result, exit)
714             VARIFY_PARAM_NULL(attrIterToken, result, exit)
715             strncpy(key, attrIterToken, strlen(attrIterToken) + 1);
716
717             attrIterToken = (char *) strtok_r(NULL, ATTR_ASSIGN,
718                     &attrIterTokenPtr);
719             VARIFY_POINTER_NULL(attrIterToken, result, exit);
720             value = (char *) OICMalloc(strlen(attrIterToken) + 1);
721             VARIFY_POINTER_NULL(value, result, exit)
722             VARIFY_PARAM_NULL(attrIterToken, result, exit)
723             strncpy(value, attrIterToken, strlen(attrIterToken) + 1);
724
725             if (strcmp(key, "uri") == 0)
726             {
727                 OIC_LOG(INFO, TAG, "Build OCAction Instance.");
728
729                 action = (OCAction*) OICMalloc(sizeof(OCAction));
730                 VARIFY_POINTER_NULL(action, result, exit)
731                 memset(action, 0, sizeof(OCAction));
732                 action->resourceUri = (char *) OICMalloc(strlen(value) + 1);
733                 VARIFY_POINTER_NULL(action->resourceUri, result, exit)
734                 VARIFY_PARAM_NULL(value, result, exit)
735                 strncpy(action->resourceUri, value, strlen(value) + 1);
736             }
737             else
738             {
739                 if ((key != NULL) && (value != NULL))
740                 {
741                     OIC_LOG(INFO, TAG, "Build OCCapability Instance.");
742
743                     capa = (OCCapability*) OICMalloc(sizeof(OCCapability));
744                     VARIFY_POINTER_NULL(capa, result, exit)
745                     memset(capa, 0, sizeof(OCCapability));
746
747                     capa->capability = (char *) OICMalloc(strlen(key) + 1);
748                     VARIFY_POINTER_NULL(capa->capability, result, exit)
749                     VARIFY_PARAM_NULL(key, result, exit)
750                     strncpy(capa->capability, key, strlen(key) + 1);
751
752                     capa->status = (char *) OICMalloc(strlen(value) + 1);
753                     VARIFY_POINTER_NULL(capa->status, result, exit)
754                     VARIFY_PARAM_NULL(value, result, exit)
755                     strncpy(capa->status, value, strlen(value) + 1);
756
757                     VARIFY_POINTER_NULL(action, result, exit)
758
759                     AddCapability(&action->head, capa);
760                 }
761             }
762
763             OCFREE(key)
764             OCFREE(value)
765             OCFREE(attr)
766
767             descIterToken = (char *) strtok_r(NULL, ATTR_DELIMITER,
768                     &descIterTokenPtr);
769         }
770
771         AddAction(&(*set)->head, action);
772         iterToken = (char *) strtok_r(NULL, ACTION_DELIMITER, &iterTokenPtr);
773         OCFREE(desc);
774     }
775
776     return OC_STACK_OK;
777 exit:
778     OCFREE(attr)
779     OCFREE(desc)
780     OCFREE(capa)
781     OCFREE(action)
782     OCFREE((*set)->actionsetName)
783     OCFREE(*set)
784     OCFREE(key)
785     OCFREE(value)
786     OCFREE(attr)
787
788     return result;
789 }
790
791 OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc)
792 {
793     // Can't use the macros here as they are hardcoded to 'exit' and will
794     // result in dereferencing a null pointer.
795     if (!actionset || !desc)
796     {
797         return OC_STACK_INVALID_PARAM;
798     }
799     char temp[1024] = { 0 };
800     size_t remaining = sizeof(temp) - 1;
801     OCStackResult res = OC_STACK_ERROR;
802     char* actionTypeStr = NULL;
803
804     OCAction *action = actionset->head;
805
806     if (remaining >= strlen(actionset->actionsetName) + 1)
807     {
808         strncat(temp, actionset->actionsetName, strlen(actionset->actionsetName));
809         remaining -= strlen(actionset->actionsetName);
810         strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
811         remaining--;
812     }
813     else
814     {
815         res = OC_STACK_ERROR;
816         goto exit;
817     }
818
819     actionTypeStr = (char *)OICMalloc(1024);
820     if(actionTypeStr != NULL)
821     {
822         sprintf(actionTypeStr, "%ld %u", actionset->timesteps, actionset->type);
823         if(remaining >= strlen(actionTypeStr) + strlen(ACTION_DELIMITER) + 1)
824         {
825             strncat(temp, actionTypeStr, strlen(actionTypeStr));
826             remaining -= strlen(actionTypeStr);
827             strncat(temp, ACTION_DELIMITER, strlen(ACTION_DELIMITER));
828             remaining -= strlen(ACTION_DELIMITER);
829             OICFree(actionTypeStr);
830         }
831         else
832         {
833             OICFree(actionTypeStr);
834             res = OC_STACK_ERROR;
835             goto exit;
836         }
837     }
838     else
839     {
840         res = OC_STACK_ERROR;
841         goto exit;
842     }
843
844     while (action != NULL)
845     {
846         if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1))
847         {
848             res = OC_STACK_ERROR;
849             goto exit;
850         }
851
852         strcat(temp, "uri=");
853         remaining -= strlen("uri=");
854         strcat(temp, action->resourceUri);
855         remaining -= strlen(action->resourceUri);
856         strcat(temp, "|");
857         remaining--;
858
859         OCCapability *capas = action->head;
860         while (capas != NULL)
861         {
862             if (remaining < (strlen(capas->capability)
863                              + 1 + strlen(capas->status)))
864             {
865                 res = OC_STACK_ERROR;
866                 goto exit;
867             }
868
869             strcat(temp, capas->capability);
870             remaining -= strlen(capas->capability);
871             strcat(temp, "=");
872             remaining--;
873             strcat(temp, capas->status);
874             remaining -= strlen(capas->status);
875
876             capas = capas->next;
877             if (capas != NULL)
878             {
879                 if (remaining < 1)
880                 {
881                     res = OC_STACK_ERROR;
882                     goto exit;
883                 }
884                 strcat(temp, "|");
885                 remaining --;
886             }
887         }
888
889         action = action->next;
890         if (action != NULL)
891         {
892             if (remaining < strlen(ACTION_DELIMITER))
893             {
894                 res = OC_STACK_ERROR;
895                 goto exit;
896             }
897             strcat(temp, ACTION_DELIMITER);
898             remaining--;
899         }
900     }
901
902     *desc = OICStrdup(temp);
903     VARIFY_POINTER_NULL(*desc, res, exit);
904
905     return OC_STACK_OK;
906
907 exit:
908     OCFREE(*desc);
909     return res;
910 }
911
912 OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle,
913         OCClientResponse* clientResponse)
914 {
915     (void)context;
916     (void)clientResponse;
917     OIC_LOG(INFO, TAG, "Entering ActionSetCB");
918
919     ClientRequestInfo *info = GetClientRequestInfo(clientRequstList, handle);
920
921     if (info)
922     {
923         OCEntityHandlerResponse response = { 0 };
924
925         response.ehResult = OC_EH_OK;
926
927         if(NULL == clientResponse->payload)
928         {
929             OIC_LOG(ERROR, TAG, "Error sending response");
930             return OC_STACK_DELETE_TRANSACTION;
931         }
932
933         // Format the response.  Note this requires some info about the request
934         response.requestHandle = info->ehRequest->requestId;
935         response.resourceHandle = info->collResource;
936         response.payload = clientResponse->payload;
937         response.numSendVendorSpecificHeaderOptions = 0;
938         memset(response.sendVendorSpecificHeaderOptions, 0,
939                 sizeof response.sendVendorSpecificHeaderOptions);
940         memset(response.resourceUri, 0, sizeof response.resourceUri);
941         // Indicate that response is NOT in a persistent buffer
942         response.persistentBufferFlag = 0;
943
944         // Send the response
945         if (OCDoResponse(&response) != OC_STACK_OK)
946         {
947             OIC_LOG(ERROR, TAG, "Error sending response");
948             return OC_STACK_DELETE_TRANSACTION;
949         }
950
951         RemoveClientRequestInfo(&clientRequstList, info);
952         OCFREE(info)
953     }
954
955     return OC_STACK_KEEP_TRANSACTION;
956 }
957
958 void ActionSetCD(void *context)
959 {
960     (void)context;
961 }
962
963 OCStackResult BuildActionJSON(OCAction* action, unsigned char* bufferPtr,
964         uint16_t *remaining)
965 {
966     OCStackResult ret = OC_STACK_ERROR;
967     cJSON *json;
968     cJSON *body;
969
970     char *jsonStr;
971     uint16_t jsonLen;
972
973     OIC_LOG(INFO, TAG, "Entering BuildActionJSON");
974     json = cJSON_CreateObject();
975
976     cJSON_AddItemToObject(json, "rep", body = cJSON_CreateObject());
977
978     OCCapability* pointerCapa = action->head;
979     while (pointerCapa)
980     {
981         cJSON_AddStringToObject(body, pointerCapa->capability,
982                 pointerCapa->status);
983         pointerCapa = pointerCapa->next;
984     }
985
986     jsonStr = cJSON_PrintUnformatted(json);
987
988     jsonLen = strlen(jsonStr);
989     if (jsonLen < *remaining)
990     {
991         strncat((char*) bufferPtr, jsonStr, jsonLen);
992         *remaining -= jsonLen;
993         bufferPtr += jsonLen;
994         ret = OC_STACK_OK;
995     }
996
997     cJSON_Delete(json);
998     free(jsonStr);
999
1000     return ret;
1001 }
1002
1003 OCPayload* BuildActionCBOR(OCAction* action)
1004 {
1005     OCRepPayload* payload = OCRepPayloadCreate();
1006
1007     if (!payload)
1008     {
1009         OIC_LOG(INFO, TAG, "Failed to create put payload object");
1010         return NULL;
1011     }
1012
1013     OCCapability* pointerCapa = action->head;
1014     while (pointerCapa)
1015     {
1016         OCRepPayloadSetPropString(payload, pointerCapa->capability, pointerCapa->status);
1017         pointerCapa = pointerCapa->next;
1018     }
1019
1020     return (OCPayload*) payload;
1021 }
1022
1023 unsigned int GetNumOfTargetResource(OCAction *actionset)
1024 {
1025     int numOfResource = 0;
1026
1027     OCAction *pointerAction = actionset;
1028
1029     while (pointerAction != NULL)
1030     {
1031         numOfResource++;
1032         pointerAction = pointerAction->next;
1033     }
1034
1035     return numOfResource;
1036 }
1037
1038 OCStackResult SendAction(OCDoHandle *handle, OCServerRequest* requestHandle, const char *targetUri,
1039         OCPayload *payload)
1040 {
1041
1042     OCCallbackData cbData;
1043     cbData.cb = &ActionSetCB;
1044     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
1045     cbData.cd = NULL;
1046
1047     return OCDoResource(handle, OC_REST_PUT, targetUri, &requestHandle->devAddr,
1048                        payload, CT_ADAPTER_IP, OC_NA_QOS, &cbData, NULL, 0);
1049 }
1050
1051 OCStackResult DoAction(OCResource* resource, OCActionSet* actionset,
1052         OCServerRequest* requestHandle)
1053 {
1054     OCStackResult result = OC_STACK_ERROR;
1055
1056     if( NULL == actionset->head)
1057     {
1058         return result;
1059     }
1060
1061     OCAction *pointerAction = actionset->head;
1062
1063     while (pointerAction != NULL)
1064     {
1065         OCPayload* payload;
1066         payload = BuildActionCBOR(pointerAction);
1067
1068         if(payload == NULL)
1069         {
1070             return result;
1071         }
1072
1073         ClientRequestInfo *info = (ClientRequestInfo *) OICMalloc(
1074                 sizeof(ClientRequestInfo));
1075
1076         if( info == NULL )
1077         {
1078             OCFREE(payload);
1079             return OC_STACK_NO_MEMORY;
1080         }
1081
1082         memset(info, 0, sizeof(ClientRequestInfo));
1083
1084         info->collResource = resource;
1085         info->ehRequest = requestHandle;
1086
1087         result = SendAction(&info->required, info->ehRequest, pointerAction->resourceUri,
1088                 payload);
1089
1090         if (result != OC_STACK_OK)
1091         {
1092             OICFree(info);
1093             return result;
1094         }
1095
1096         AddClientRequestInfo(&clientRequstList, info);
1097
1098         pointerAction = pointerAction->next;
1099     }
1100
1101     return result;
1102 }
1103
1104 void DoScheduledGroupAction()
1105 {
1106     OIC_LOG(INFO, TAG, "DoScheduledGroupAction Entering...");
1107     ScheduledResourceInfo* info = GetScheduledResource(g_scheduleResourceList);
1108
1109     if (info == NULL)
1110     {
1111         OIC_LOG(INFO, TAG, "Target resource is NULL");
1112         goto exit;
1113     }
1114     else if (info->resource == NULL)
1115     {
1116         OIC_LOG(INFO, TAG, "Target resource is NULL");
1117         goto exit;
1118     }
1119     else if (info->actionset == NULL)
1120     {
1121         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1122         goto exit;
1123     }
1124     else if (info->ehRequest == NULL)
1125     {
1126         OIC_LOG(INFO, TAG, "Target ActionSet is NULL");
1127         goto exit;
1128     }
1129
1130     MUTEX_LOCK(&g_scheduledResourceLock);
1131
1132     DoAction(info->resource, info->actionset, info->ehRequest);
1133
1134     MUTEX_UNLOCK(&g_scheduledResourceLock);
1135
1136
1137     if (info->actionset->type == RECURSIVE)
1138     {
1139         ScheduledResourceInfo *schedule;
1140         schedule = (ScheduledResourceInfo *) OICMalloc(
1141                 sizeof(ScheduledResourceInfo));
1142
1143         if (schedule)
1144         {
1145             OIC_LOG(INFO, TAG, "Building New Call Info.");
1146             memset(schedule, 0, sizeof(ScheduledResourceInfo));
1147
1148             if (info->actionset->timesteps > 0)
1149             {
1150                 MUTEX_LOCK(&g_scheduledResourceLock);
1151                 schedule->resource = info->resource;
1152                 schedule->actionset = info->actionset;
1153                 schedule->ehRequest = info->ehRequest;
1154
1155                 schedule->time = registerTimer(info->actionset->timesteps,
1156                         &schedule->timer_id,
1157                         &DoScheduledGroupAction);
1158
1159                 OIC_LOG(INFO, TAG, "Reregistration.");
1160                 MUTEX_UNLOCK(&g_scheduledResourceLock);
1161                 AddScheduledResource(&g_scheduleResourceList, schedule);
1162             }
1163             else
1164             {
1165                 OICFree(schedule);
1166             }
1167         }
1168     }
1169
1170     RemoveScheduledResource(&g_scheduleResourceList, info);
1171
1172     exit:
1173
1174     return;
1175 }
1176
1177 OCStackResult BuildCollectionGroupActionCBORResponse(
1178         OCMethod method/*OCEntityHandlerFlag flag*/, OCResource *resource,
1179         OCEntityHandlerRequest *ehRequest)
1180 {
1181     OCStackResult stackRet = OC_STACK_ERROR;
1182
1183     OIC_LOG(INFO, TAG, "Group Action is requested.");
1184
1185     char *doWhat = NULL;
1186     char *details = NULL;
1187
1188     stackRet = ExtractKeyValueFromRequest(ehRequest, &doWhat, &details);
1189
1190     if(stackRet != OC_STACK_OK)
1191     {
1192         OIC_LOG_V(ERROR, TAG, "ExtractKeyValueFromRequest failed: %d", stackRet);
1193         return stackRet;
1194     }
1195
1196     stackRet = OC_STACK_ERROR;
1197
1198     if (method == OC_REST_PUT)
1199     {
1200         OIC_LOG(INFO, TAG, "Group Action[PUT].");
1201
1202         if (strcmp(doWhat, ACTIONSET) == 0)
1203         {
1204             OCActionSet *actionSet = NULL;
1205             stackRet = BuildActionSetFromString(&actionSet, details);
1206
1207             if(stackRet == OC_STACK_OK)
1208             {
1209                 if (actionSet != NULL)
1210                 {
1211                     stackRet = AddActionSet(&resource->actionsetHead,
1212                             actionSet);
1213                     if (stackRet == OC_STACK_ERROR)
1214                     {
1215                         if(actionSet != NULL)
1216                         {
1217                             DeleteActionSet( &actionSet );
1218                         }
1219                         OIC_LOG(INFO, TAG, "Duplicated ActionSet ");
1220                     }
1221                 }
1222                 else
1223                 {
1224                     stackRet = OC_STACK_ERROR;
1225                     goto exit;
1226                 }
1227             }
1228             else
1229             {
1230                 stackRet = OC_STACK_ERROR;
1231             }
1232
1233         }
1234         else if (strcmp(doWhat, DELETE_ACTIONSET) == 0)
1235         {
1236             if (FindAndDeleteActionSet(&resource, details) == OC_STACK_OK)
1237             {
1238                 stackRet = OC_STACK_OK;
1239             }
1240             else
1241             {
1242                 stackRet = OC_STACK_ERROR;
1243             }
1244         }
1245
1246         OCRepPayload* payload = OCRepPayloadCreate();
1247
1248         if(!payload)
1249         {
1250             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1251             stackRet = OC_STACK_ERROR;
1252         }
1253         else
1254         {
1255             OCEntityHandlerResponse response = { 0 };
1256
1257             if(stackRet == OC_STACK_OK)
1258                 response.ehResult = OC_EH_OK;
1259             else
1260                 response.ehResult = OC_EH_ERROR;
1261
1262             // Format the response.  Note this requires some info about the request
1263             response.requestHandle = ehRequest->requestHandle;
1264             response.resourceHandle = ehRequest->resource;
1265             response.payload = (OCPayload*) payload;
1266             response.numSendVendorSpecificHeaderOptions = 0;
1267             memset(response.sendVendorSpecificHeaderOptions, 0,
1268                     sizeof response.sendVendorSpecificHeaderOptions);
1269             memset(response.resourceUri, 0, sizeof response. resourceUri);
1270             // Indicate that response is NOT in a persistent buffer
1271             response.persistentBufferFlag = 0;
1272             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1273
1274             // Send the response
1275             if (OCDoResponse(&response) != OC_STACK_OK)
1276             {
1277                 OIC_LOG(ERROR, TAG, "Error sending response");
1278                 stackRet = OC_STACK_ERROR;
1279             }
1280         }
1281         OCRepPayloadDestroy(payload);
1282     }
1283     else if (method == OC_REST_POST)
1284     {
1285         OCActionSet *actionset = NULL;
1286
1287         OCRepPayload* payload = OCRepPayloadCreate();
1288         OCRepPayloadSetUri(payload, resource->uri);
1289
1290         if ((strcmp(doWhat, DO_ACTION) == 0)
1291                 || (strcmp(doWhat, "DoScheduledAction") == 0))
1292         {
1293             char *pActionsetName = NULL;
1294             long int delay = -1;
1295
1296             if (strcmp(doWhat, "DoScheduledAction") == 0)
1297             {
1298                 stackRet = ExtractActionSetNameAndDelaytime(details,
1299                         &pActionsetName, &delay);
1300
1301                 OCFREE(details)
1302                 details = pActionsetName;
1303             }
1304             else
1305             {
1306                 stackRet = OC_STACK_OK;
1307             }
1308
1309             if (stackRet == OC_STACK_OK)
1310             {
1311                 if (GetActionSet(details, resource->actionsetHead,
1312                         &actionset) != OC_STACK_OK)
1313                 {
1314                     OIC_LOG(INFO, TAG, "ERROR");
1315                     stackRet = OC_STACK_ERROR;
1316                 }
1317
1318                 if (actionset == NULL)
1319                 {
1320                     OIC_LOG(INFO, TAG, "Cannot Find ActionSet");
1321                     stackRet = OC_STACK_ERROR;
1322                 }
1323                 else
1324                 {
1325                     OIC_LOG(INFO, TAG, "Group Action[POST].");
1326                     OCServerRequest *request =
1327                             GetServerRequestUsingHandle(ehRequest->requestHandle);
1328                     if (NULL == request)
1329                     {
1330                         stackRet = OC_STACK_ERROR;
1331                         goto exit;
1332                     }
1333
1334                     if (actionset->type == NONE)
1335                     {
1336                         OIC_LOG_V(INFO, TAG, "Execute ActionSet : %s",
1337                                 actionset->actionsetName);
1338                         unsigned int num = GetNumOfTargetResource(
1339                                 actionset->head);
1340
1341                         request->ehResponseHandler = HandleAggregateResponse;
1342                         request->numResponses = num + 1;
1343
1344                         DoAction(resource, actionset, request);
1345
1346                         stackRet = OC_STACK_OK;
1347                     }
1348                     else
1349                     {
1350                         OIC_LOG_V(INFO, TAG, "Execute Scheduled ActionSet : %s",
1351                                 actionset->actionsetName);
1352
1353                         delay =
1354                                 (delay == -1 ? actionset->timesteps : delay);
1355
1356                         ScheduledResourceInfo *schedule;
1357                         schedule = (ScheduledResourceInfo *) OICMalloc(
1358                                 sizeof(ScheduledResourceInfo));
1359
1360                         if (schedule)
1361                         {
1362                             OIC_LOG(INFO, TAG, "Building New Call Info.");
1363                             memset(schedule, 0,
1364                                     sizeof(ScheduledResourceInfo));
1365                             MUTEX_LOCK(&g_scheduledResourceLock);
1366                             schedule->resource = resource;
1367                             schedule->actionset = actionset;
1368                             schedule->ehRequest = request;
1369
1370                             MUTEX_UNLOCK(&g_scheduledResourceLock);
1371                             if (delay > 0)
1372                             {
1373                                 OIC_LOG_V(INFO, TAG, "delay_time is %ld seconds.",
1374                                         actionset->timesteps);
1375                                 MUTEX_LOCK(&g_scheduledResourceLock);
1376                                 schedule->time = registerTimer(delay,
1377                                         &schedule->timer_id,
1378                                         &DoScheduledGroupAction);
1379                                 MUTEX_UNLOCK(&g_scheduledResourceLock);
1380                                 AddScheduledResource(&g_scheduleResourceList,
1381                                         schedule);
1382                                 stackRet = OC_STACK_OK;
1383                             }
1384                             else
1385                             {
1386                                 stackRet = OC_STACK_ERROR;
1387                             }
1388                         }
1389                     }
1390                 }
1391             }
1392         }
1393         else if (strcmp(doWhat, "CancelAction") == 0)
1394         {
1395             ScheduledResourceInfo *info =
1396                     GetScheduledResourceByActionSetName(g_scheduleResourceList, details);
1397
1398             if(info != NULL)
1399             {
1400                 MUTEX_LOCK(&g_scheduledResourceLock);
1401                 unregisterTimer(info->timer_id);
1402                 MUTEX_UNLOCK(&g_scheduledResourceLock);
1403
1404                 RemoveScheduledResource(&g_scheduleResourceList, info);
1405                 stackRet = OC_STACK_OK;
1406             }
1407             else
1408             {
1409                 stackRet = OC_STACK_ERROR;
1410             }
1411         }
1412
1413         else if (strcmp(doWhat, GET_ACTIONSET) == 0)
1414         {
1415             char *plainText = NULL;
1416             OCActionSet *actionset = NULL;
1417
1418             GetActionSet(details, resource->actionsetHead, &actionset);
1419             if (actionset != NULL)
1420             {
1421                 BuildStringFromActionSet(actionset, &plainText);
1422
1423                 if (plainText != NULL)
1424                 {
1425                     OCRepPayloadSetPropString(payload, ACTIONSET, plainText);
1426                 }
1427                 OICFree(plainText);
1428                 stackRet = OC_STACK_OK;
1429             }
1430         }
1431
1432         if(!payload)
1433         {
1434             OIC_LOG(ERROR, TAG, "Failed to allocate Payload");
1435             stackRet = OC_STACK_ERROR;
1436         }
1437         else
1438         {
1439             OCEntityHandlerResponse response = { 0 };
1440             if(stackRet == OC_STACK_OK)
1441                 response.ehResult = OC_EH_OK;
1442             else
1443                 response.ehResult = OC_EH_ERROR;
1444
1445             // Format the response.  Note this requires some info about the request
1446             response.requestHandle = ehRequest->requestHandle;
1447             response.resourceHandle = ehRequest->resource;
1448             response.payload = (OCPayload*) payload;
1449             response.numSendVendorSpecificHeaderOptions = 0;
1450             memset(response.sendVendorSpecificHeaderOptions, 0,
1451                     sizeof response.sendVendorSpecificHeaderOptions);
1452             memset(response.resourceUri, 0, sizeof response.resourceUri);
1453             // Indicate that response is NOT in a persistent buffer
1454             response.persistentBufferFlag = 0;
1455             response.ehResult = (stackRet == OC_STACK_OK)?OC_EH_OK:OC_EH_ERROR;
1456
1457             // Send the response
1458             if (OCDoResponse(&response) != OC_STACK_OK)
1459             {
1460                 OIC_LOG(ERROR, TAG, "Error sending response");
1461                 stackRet = OC_STACK_ERROR;
1462             }
1463         }
1464         OCRepPayloadDestroy(payload);
1465     }
1466
1467 exit:
1468
1469     OCFREE(doWhat)
1470     OCFREE(details)
1471
1472     return stackRet;
1473 }
1474
1475 OCStackResult InitializeScheduleResourceList()
1476 {
1477     MUTEX_INITIALIZE(&g_scheduledResourceLock);
1478
1479     g_scheduleResourceList = NULL;
1480     return OC_STACK_OK;
1481 }
1482
1483 void TerminateScheduleResourceList()
1484 {
1485     assert(g_scheduleResourceList == NULL);
1486
1487     MUTEX_TERMINATE(&g_scheduledResourceLock);
1488 }