1use chrono::{DateTime, FixedOffset};
2use libcwtch::structs::*;
3use libcwtch::CwtchLib;
4use libcwtch::event::{ContactIdentity, ConversationID, Event};
5use libcwtch::structs::MessageType::InviteGroup;
6
7use crate::behaviour::{Behaviour, ContactInteractionPolicy, GroupInteractionPolicy, GroupInvitePolicy, NewContactPolicy};
8use crate::behaviour::NewContactPolicy::AllowList;
9
10pub trait EventHandler {
13 #[allow(unused_variables)]
14 fn handle(&mut self, cwtch: &dyn libcwtch::CwtchLib, profile: Option<&Profile>, event: &Event) {}
15
16 #[allow(unused_variables)]
17 fn on_contact_online(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: ConversationID) {}
18 #[allow(unused_variables)]
19 fn on_new_contact(&self, cwtch: &dyn libcwtch::CwtchLib, profile: &Profile, convo_id: ConversationID) {}
20 #[allow(unused_variables)]
21 fn on_new_message_from_contact(&mut self, cwtch: &dyn libcwtch::CwtchLib, behaviour: &mut Behaviour, profile: &Profile, conversation_id: ConversationID, handle: String, timestamp_received: DateTime<FixedOffset>, message: MessageWrapper) {}
22
23 #[allow(unused_variables)]
24 fn on_new_message_from_group(&mut self, cwtch: &dyn libcwtch::CwtchLib, behaviour: &mut Behaviour, profile: &Profile, conversation_id: ConversationID, contact: ContactIdentity, timestamp_sent: DateTime<FixedOffset>, message: MessageWrapper) {}
25}
26
27pub struct Imp {
29 cwtch: Box<dyn libcwtch::CwtchLib>,
30 behaviour: Behaviour,
31 password: String,
32 home_dir: String,
33
34 settings: Option<Settings>,
35 profile: Option<Profile>,
36}
37
38impl Imp {
39 pub fn spawn(behaviour: Behaviour, password: String, home_dir: String) -> Self {
42 let cwtch = libcwtch::new_cwtchlib_go();
43 println!("start_cwtch");
44 let ret = cwtch.start_cwtch(&home_dir, "");
45 println!("start_cwtch returned {}", ret);
46
47 return Imp {
48 behaviour,
49 cwtch: Box::new(cwtch),
50 password,
51 home_dir,
52 profile: None,
53 settings: None,
54 };
55 }
56
57 pub fn behaviour_mut(&self) -> &Behaviour {
58 &self.behaviour
59 }
60 pub fn behaviour_allowlist_add(&mut self, contact: ContactIdentity) {
61 self.behaviour.allow_list.peers.push(contact);
62 }
63
64 pub fn behaviour_allowlist_rm(&mut self, contact: ContactIdentity) {
65 if let Some(index) = self.behaviour.allow_list.peers.iter().position(|c| *c == contact) {
66 self.behaviour.allow_list.peers.remove(index);
67 }
68 }
69
70 #[allow(unused_variables, unused_mut)]
72 pub fn event_loop<T>(&mut self, handler: &mut T)
73 where
74 T: EventHandler,
75 {
76 let mut initialized: bool = false;
77
78 loop {
79 let event = self.cwtch.get_appbus_event();
80
81 match &event {
82 Event::CwtchStarted => {
83 println!("Cwtch Started");
84 initialized = true;
85
86 if self.profile.is_none() {
87 self.cwtch.load_profiles(&self.password);
88 }
89 }
90 Event::UpdateGlobalSettings { settings } => {
91 let mut local_settings = settings.clone();
92 println!("Loading settings froms {:?}", local_settings);
93
94 if self.behaviour.proto_experiments {
95 local_settings.ExperimentsEnabled = true;
96 }
97 if self.behaviour.proto_experiment_fileshare {
98 local_settings
99 .Experiments
100 .insert(Experiments::FileSharingExperiment.to_key_string(), true);
101 }
102 if self.behaviour.proto_experiment_groups {
103 local_settings
104 .Experiments
105 .insert(Experiments::GroupExperiment.to_key_string(), true);
106 }
107 match local_settings.save(self.cwtch.as_ref()) {
108 Ok(_) => (),
109 Err(e) => println!("ERROR: could not save settings: {}", e),
110 };
111
112 match self.profile.as_ref() {
113 Some(profile) => {
114 if let Some(profile_pic_path) = &self.behaviour.profile_pic_path {
115 self.cwtch.share_file(&profile.profile_id, ConversationID(-1), profile_pic_path);
116 }
117 }
118 None => (),
119 };
120
121 self.settings = Some(local_settings);
122 }
123 Event::NewPeer { profile_id, tag, created, name, default_picture, picture, online, profile_data} => {
124 if let Err(e) = profile_data {
125 panic!("error parsing profile: {}", e);
126 }
127
128 self.cwtch.set_profile_attribute(
129 &profile_id,
130 "profile.name",
131 &self.behaviour.profile_name,
132 );
133
134 if let Ok(ok_profile) = profile_data {
135 for (_id, conversation) in &ok_profile.conversations {
136 self.process_contact(conversation.identifier);
137 }
138
139 if let AllowList = &self.behaviour.new_contant_policy {
141 for contact_id in &self.behaviour.allow_list.peers {
142 if let None = ok_profile.find_conversation_id_by_handle(contact_id.clone()) {
143 self.cwtch.import_bundle(&profile_id, contact_id.clone().as_str());
144 }
145 }
146 }
147
148 self.profile = Some(ok_profile.clone());
149 }
150 }
151 Event::AppError { error, data } => {
152 if initialized && error == "Loaded 0 profiles" {
153 if self.profile.is_none() {
154 self.cwtch
155 .create_profile(&self.behaviour.profile_name, &self.password, true);
156 }
157 }
158 }
159 Event::ContactCreated {profile_id, conversation_id, contact_id, nick, status, unread, picture, default_picture, num_messages, accepted, access_control_list, blocked, loading, last_msg_time, .. } => {
160 let conversation = Conversation {
161 contact_id: contact_id.clone(),
162 identifier: conversation_id.clone(),
163 name: nick.clone(),
164 status: status.clone(),
165 blocked: blocked.clone(),
166 accepted: accepted.clone(),
167 access_control_list: access_control_list.clone(),
168 is_group: false, };
170
171 self.process_contact(conversation.identifier);
172
173 match self.profile.as_mut() {
174 Some(profile) => {
175 profile
176 .conversations
177 .insert(conversation.identifier, conversation);
178 handler.on_new_contact(self.cwtch.as_ref(), profile, conversation_id.clone());
179 handler.on_contact_online(self.cwtch.as_ref(), profile, conversation_id.clone());
180 }
181 None => (),
182 };
183 }
184 Event::PeerStateChange { profile_id, contact_id, connection_state } => {
185 if *connection_state == ConnectionState::Authenticated {
186 match self.profile.as_ref() {
187 Some(profile) => {
188 match profile.find_conversation_id_by_handle(contact_id.clone()) {
189 Some(conversation_id) => handler.on_contact_online(self.cwtch.as_ref(), profile,conversation_id),
190 None => {}
191 }
192 }
193 None => (),
194 };
195 }
196 }
197 Event::NewMessageFromPeer {profile_id, conversation_id,contact_id, nick, timestamp_received, message, notification, picture } => {
198 if message.o == InviteGroup {
199 if let Some(profile) = self.profile.as_ref() {
200 match &self.behaviour.group_invite_policy {
201 GroupInvitePolicy::Ignore => (),
202 GroupInvitePolicy::Accept => self.cwtch.import_bundle(profile_id, message.d.as_str()),
203 GroupInvitePolicy::AcceptFromContact=> {
204 if profile.conversations[conversation_id].accepted {
205 self.cwtch.import_bundle(profile_id, message.d.as_str())
206 }
207 }
208 GroupInvitePolicy::AllowList => {
209 if let Some(conversation) = profile.conversations.get(&conversation_id) {
210 if self.behaviour.allow_list.peers.contains(&conversation.contact_id) {
211 self.cwtch.import_bundle(profile_id, message.d.as_str())
212 }
213 }
214 }
215 }
216 }
217 } else {
218 if let Some(profile) = self.profile.as_ref() {
219 match &self.behaviour.contact_interaction_policy {
220 ContactInteractionPolicy::Ignore => (),
221 ContactInteractionPolicy::Accept => handler.on_new_message_from_contact(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone()),
222 ContactInteractionPolicy::AcceptFromContact=> {
223 if profile.conversations[conversation_id].accepted {
224 handler.on_new_message_from_contact(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone());
225 }
226 },
227 ContactInteractionPolicy::AllowList => {
228 if let Some(conversation) = profile.conversations.get(&conversation_id) {
229 if self.behaviour.allow_list.peers.contains(&conversation.contact_id) {
230 handler.on_new_message_from_contact(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), nick.clone(), timestamp_received.clone(), message.clone());
231 }
232 }
233 }
234 }
235 }
236 }
237 }
238 Event::NewMessageFromGroup { profile_id, conversation_id, timestamp_sent, contact_id, index, message, content_hash, picture, notification, } => {
239 if let Some(profile) = self.profile.as_ref() {
240 match &self.behaviour.group_interaction_policy {
241 GroupInteractionPolicy::Ignore => (),
242 GroupInteractionPolicy::Accept => handler.on_new_message_from_group(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), contact_id.clone(), timestamp_sent.clone(), message.clone()),
243 GroupInteractionPolicy::AcceptFromContact=> {
244 if let Some(contact_convo_id) = profile.find_conversation_id_by_handle(contact_id.clone()) {
245 if profile.conversations[&contact_convo_id].accepted {
246 handler.on_new_message_from_group(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), contact_id.clone(), timestamp_sent.clone(), message.clone())
247 }
248 }
249 },
250 GroupInteractionPolicy::AllowList => {
251 if self.behaviour.allow_list.peers.contains(&contact_id) {
252 handler.on_new_message_from_group(self.cwtch.as_ref(), &mut self.behaviour, profile, conversation_id.clone(), contact_id.clone(), timestamp_sent.clone(), message.clone())
253 }
254 }
255 }
256 }
257 }
258 Event::ErrUnhandled { name, data } => eprintln!("unhandled event: {}!", name),
259 _ => (),
260 };
261
262 handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), &event);
263 }
264 }
265
266 fn process_contact(&self, conversation_id: ConversationID) {
267 match &self.profile {
268 Some(profile) => {
269 let profile_handle = profile.profile_id.clone();
270 match &self.behaviour.new_contant_policy {
271 NewContactPolicy::Accept => {
272 self.cwtch
273 .accept_conversation(&profile.profile_id, conversation_id);
274 }
275 NewContactPolicy::Block => self.cwtch.block_conversation(&profile_handle.clone(), conversation_id),
276 NewContactPolicy::AllowList => {
277 match profile.conversations.get(&conversation_id) {
278 Some(conversation) => {
279 if self.behaviour.allow_list.peers.contains(&conversation.contact_id) {
280 self.cwtch
281 .accept_conversation(&profile_handle.clone(), conversation_id);
282 } else {
283 self.cwtch.block_conversation(&profile_handle.clone(), conversation_id);
284 }
285 },
286 None => {},
287 }
288 }
289 NewContactPolicy::Ignore => (),
290 }
291 },
292 None => {},
293 }
294 }
295}