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