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