1/*
2 * Copyright 2015-2016, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "People.h"
8
9#include <stdio.h>
10
11#include <Autolock.h>
12#include <Node.h>
13
14
15static BString
16PersonName(BNode& node)
17{
18	BString fullName;
19	node.ReadAttrString("META:name", &fullName);
20
21	return fullName;
22}
23
24
25static void
26AddPersonAddresses(BNode& node, BStringList& addresses)
27{
28	BString email;
29	if (node.ReadAttrString("META:email", &email) != B_OK || email.IsEmpty())
30		return;
31
32	addresses.Add(email);
33
34	// Support for 3rd-party People apps
35	for (int i = 2; i < 99; i++) {
36		char attr[32];
37		snprintf(attr, sizeof(attr), "META:email%d", i);
38
39		if (node.ReadAttrString(attr, &email) != B_OK)
40			break;
41
42		addresses.Add(email);
43	}
44}
45
46
47static void
48AddPersonGroups(BNode& node, BStringList& groups)
49{
50	BString groupString;
51	if (node.ReadAttrString("META:group", &groupString) != B_OK
52		|| groupString.IsEmpty()) {
53		return;
54	}
55
56	int first = 0;
57	while (first < groupString.Length()) {
58		int end = groupString.FindFirst(',', first);
59		if (end < 0)
60			end = groupString.Length();
61
62		BString group;
63		groupString.CopyInto(group, first, end - first);
64		group.Trim();
65		groups.Add(group);
66
67		first = end + 1;
68	}
69}
70
71
72// #pragma mark - Person
73
74
75Person::Person(const entry_ref& ref)
76{
77	BNode node(&ref);
78	if (node.InitCheck() != B_OK)
79		return;
80
81	fName = PersonName(node);
82	AddPersonAddresses(node, fAddresses);
83	AddPersonGroups(node, fGroups);
84}
85
86
87Person::~Person()
88{
89}
90
91
92bool
93Person::IsInGroup(const char* group) const
94{
95	for (int32 index = 0; index < CountGroups(); index++) {
96		if (GroupAt(index) == group)
97			return true;
98	}
99	return false;
100}
101
102
103// #pragma mark - PersonList
104
105
106PersonList::PersonList(QueryList& query)
107	:
108	fQueryList(query),
109	fPersons(10, true)
110{
111	fQueryList.AddListener(this);
112}
113
114
115PersonList::~PersonList()
116{
117	fQueryList.RemoveListener(this);
118}
119
120
121void
122PersonList::EntryCreated(QueryList& source, const entry_ref& ref, ino_t node)
123{
124	BAutolock locker(this);
125
126	Person* person = new Person(ref);
127	fPersons.AddItem(person);
128	fPersonMap.insert(std::make_pair(node_ref(ref.device, node), person));
129}
130
131
132void
133PersonList::EntryRemoved(QueryList& source, const node_ref& nodeRef)
134{
135	BAutolock locker(this);
136
137	PersonMap::iterator found = fPersonMap.find(nodeRef);
138	if (found != fPersonMap.end()) {
139		Person* person = found->second;
140		fPersonMap.erase(found);
141		fPersons.RemoveItem(person);
142	}
143}
144
145
146// #pragma mark - GroupList
147
148
149GroupList::GroupList(QueryList& query)
150	:
151	fQueryList(query)
152{
153	fQueryList.AddListener(this);
154}
155
156
157GroupList::~GroupList()
158{
159	fQueryList.RemoveListener(this);
160}
161
162
163void
164GroupList::EntryCreated(QueryList& source, const entry_ref& ref, ino_t _node)
165{
166	BNode node(&ref);
167	if (node.InitCheck() != B_OK)
168		return;
169
170	BAutolock locker(this);
171
172	BStringList groups;
173	AddPersonGroups(node, groups);
174
175	for (int32 index = 0; index < groups.CountStrings(); index++) {
176		BString group = groups.StringAt(index);
177
178		StringCountMap::iterator found = fGroupMap.find(group);
179		if (found != fGroupMap.end())
180			found->second++;
181		else {
182			fGroupMap[group] = 1;
183			fGroups.Add(group);
184		}
185	}
186
187	// TODO: sort groups
188}
189
190
191void
192GroupList::EntryRemoved(QueryList& source, const node_ref& nodeRef)
193{
194	// TODO!
195}
196