1 //////////////////////////////////////////////////////////////////////
2 //
3 // BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi
4 //
5 // BeeBEEP is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation, either version 3 of the License,
8 // or (at your option) any later version.
9 //
10 // BeeBEEP is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with BeeBEEP. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>
19 //
20 // $Id: CoreShareDesktop.cpp 1455 2020-12-23 10:17:53Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "BeeUtils.h"
25 #include "ChatManager.h"
26 #include "Connection.h"
27 #include "Core.h"
28 #include "IconManager.h"
29 #include "ImageOptimizer.h"
30 #include "Protocol.h"
31 #include "Screenshot.h"
32 #include "ShareDesktop.h"
33 #include "Settings.h"
34 #include "UserManager.h"
35
36
startShareDesktop(VNumber user_id)37 bool Core::startShareDesktop( VNumber user_id )
38 {
39 if( !Settings::instance().enableShareDesktop() )
40 return false;
41
42 User u = UserManager::instance().findUser( user_id );
43 if( !u.isValid() )
44 {
45 qWarning() << "Invalid user" << user_id << "found in Core::startShareDesktop(...)";
46 return false;
47 }
48
49 QString sHtmlMsg;
50 if( u.protocolVersion() < SHARE_DESKTOP_PROTO_VERSION )
51 {
52 sHtmlMsg = tr( "%1 You cannot share desktop with %2." ).arg( IconManager::instance().toHtml( "desktop-share-refused.png", "*G*" ), Bee::userNameToShow( u, true ) );
53 dispatchSystemMessage( ID_DEFAULT_CHAT, user_id, sHtmlMsg, DispatchToAllChatsWithUser, ChatMessage::System, false );
54 qDebug() << "You cannot share desktop with" << qPrintable( u.path() ) << "with old protocol" << u.protocolVersion();
55 emit shareDesktopUpdate( u );
56 return false;
57 }
58
59 if( !mp_shareDesktop->addUserId( user_id ) )
60 {
61 emit shareDesktopUpdate( u );
62 return false;
63 }
64
65 sHtmlMsg = tr( "%1 You start to share desktop with %2." ).arg( IconManager::instance().toHtml( "desktop-share.png", "*G*" ), Bee::userNameToShow( u, true ) );
66 dispatchSystemMessage( ID_DEFAULT_CHAT, user_id, sHtmlMsg, DispatchToAllChatsWithUser, ChatMessage::System, false );
67 qDebug() << "Start to share desktop with" << qPrintable( u.path() );
68 if( !mp_shareDesktop->isActive() )
69 mp_shareDesktop->start();
70 emit shareDesktopUpdate( u );
71 return true;
72 }
73
stopShareDesktop(VNumber user_id)74 void Core::stopShareDesktop( VNumber user_id )
75 {
76 if( !mp_shareDesktop->isActive() )
77 return;
78
79 if( !mp_shareDesktop->userIdList().contains( user_id ) )
80 return;
81
82 mp_shareDesktop->removeUserId( user_id );
83 if( !mp_shareDesktop->hasUsers() )
84 mp_shareDesktop->stop();
85
86 User u = UserManager::instance().findUser( user_id );
87 if( u.isValid() )
88 {
89 QString sHtmlMsg = tr( "%1 You stop to share desktop with %2." ).arg( IconManager::instance().toHtml( "desktop-share-refused.png", "*G*" ), Bee::userNameToShow( u, true ) );
90 dispatchSystemMessage( ID_DEFAULT_CHAT, ID_LOCAL_USER, sHtmlMsg, DispatchToAllChatsWithUser, ChatMessage::System, false );
91 sendMessageToLocalNetwork( u, Protocol::instance().shareDesktopImageDataToMessage( ShareDesktopData( "", "png", false, 0 ) ) ); // Empty image stops desktop sharing
92 emit shareDesktopUpdate( u );
93 }
94 }
95
stopShareDesktop()96 void Core::stopShareDesktop()
97 {
98 foreach( VNumber user_id, mp_shareDesktop->userIdList() )
99 stopShareDesktop( user_id );
100 }
101
refuseToViewShareDesktop(VNumber from_user_id,VNumber to_user_id)102 void Core::refuseToViewShareDesktop( VNumber from_user_id, VNumber to_user_id )
103 {
104 if( from_user_id != ID_LOCAL_USER )
105 {
106 if( !mp_shareDesktop->isActive() )
107 return;
108 }
109
110 User from_user = UserManager::instance().findUser( from_user_id );
111 if( !from_user.isValid() )
112 {
113 qWarning() << "Invalid from user" << from_user_id << "found in Core::refuseToViewShareDesktop(...)";
114 return;
115 }
116
117 User to_user = UserManager::instance().findUser( to_user_id );
118 if( !to_user.isValid() )
119 {
120 qWarning() << "Invalid from user" << to_user_id << "found in Core::refuseToViewShareDesktop(...)";
121 return;
122 }
123
124 if( from_user.isLocal() )
125 {
126 qDebug() << "You have finished to view the desktop shared by" << qPrintable( to_user.path() );
127 Message m = Protocol::instance().refuseToViewDesktopShared();
128 sendMessageToLocalNetwork( to_user, m );
129 }
130 else
131 {
132 qDebug() << qPrintable( from_user.path() ) << "has closed the view of your shared desktop";
133 QString sHtmlMsg = tr( "%1 %2 has closed the view of your shared desktop." ).arg( IconManager::instance().toHtml( "desktop-share-refused.png", "*G*" ), from_user.name() );
134 dispatchSystemMessage( ID_DEFAULT_CHAT, from_user.id(), sHtmlMsg, DispatchToAllChatsWithUser, ChatMessage::System, false );
135 stopShareDesktop( from_user_id );
136 }
137 }
138
shareDesktopIsActive(VNumber user_id) const139 bool Core::shareDesktopIsActive( VNumber user_id ) const
140 {
141 if( user_id == ID_INVALID )
142 return mp_shareDesktop->isActive() && mp_shareDesktop->userIdList().size() > 0;
143 else
144 return mp_shareDesktop->isActive() && mp_shareDesktop->userIdList().contains( user_id );
145 }
146
onShareDesktopImageAvailable(const ShareDesktopData & sdd)147 void Core::onShareDesktopImageAvailable( const ShareDesktopData& sdd )
148 {
149 if( !mp_shareDesktop->isActive() )
150 return;
151
152 if( mp_shareDesktop->userIdList().isEmpty() )
153 {
154 stopShareDesktop();
155 return;
156 }
157
158 Message m = Protocol::instance().shareDesktopImageDataToMessage( sdd );
159 foreach( VNumber user_id, mp_shareDesktop->userIdList() )
160 {
161 if( mp_shareDesktop->hasUserReadImage( user_id ) )
162 {
163 Connection* c = connection( user_id );
164 if( c && c->isConnected() )
165 {
166 if( c->sendMessage( m ) )
167 {
168 #ifdef BEEBEEP_DEBUG
169 qDebug() << "Share desktop send image" << qPrintable( sdd.imageType() ) << "message with size" << m.text().size() << "to user" << user_id;
170 #endif
171 mp_shareDesktop->resetUserReadImage( user_id );
172 }
173 }
174 }
175 }
176 }
177
parseShareDesktopMessage(const User & u,const Message & m)178 void Core::parseShareDesktopMessage( const User& u, const Message& m )
179 {
180 if( m.hasFlag( Message::Refused ) )
181 {
182 #ifdef BEEBEEP_DEBUG
183 qDebug() << qPrintable( u.path() ) << "refuse your share desktop message";
184 #endif
185 refuseToViewShareDesktop( u.id(), ID_LOCAL_USER );
186 }
187 else if( m.hasFlag( Message::Request ) )
188 {
189 #ifdef BEEBEEP_DEBUG
190 qDebug() << qPrintable( u.path() ) << "has request new desktop share image";
191 #endif
192 mp_shareDesktop->requestImageFromUser( u.id() );
193 }
194 else if( m.hasFlag( Message::Private ) )
195 {
196 if( Settings::instance().enableShareDesktop() )
197 {
198 ShareDesktopData sdd = Protocol::instance().imageDataFromShareDesktopMessage( m );
199 QImage img = ImageOptimizer::instance().loadImage( sdd.imageData(), sdd.imageType(), sdd.isCompressed() );
200 if( img.isNull() )
201 qDebug() << qPrintable( u.path() ) << "has sent a NULL image and has finished to share desktop with you";
202 else
203 sendMessageToLocalNetwork( u, Protocol::instance().readImageFromDesktopShared() );
204 emit shareDesktopImageAvailable( u, img, sdd.imageType(), sdd.diffColor() );
205 }
206 else
207 {
208 refuseToViewShareDesktop( ID_LOCAL_USER, u.id() );
209 qDebug() << "You have refused to view the shared desktop because the option is disabled";
210 }
211 }
212 else
213 {
214 qWarning() << "Invalid flag found in desktop share message from user" << qPrintable( u.path() );
215 }
216 }
217
sendScreenshotToChat(VNumber chat_id)218 bool Core::sendScreenshotToChat( VNumber chat_id )
219 {
220 Chat c = ChatManager::instance().chat( chat_id );
221 if( !c.isValid() )
222 {
223 qWarning() << "Invalid chat" << chat_id << "found in Core::sendScreenshotToChat(...)";
224 return false;
225 }
226
227 Screenshot screen_shot;
228 screen_shot.grabPrimaryScreen();
229
230 if( !screen_shot.isValid() )
231 {
232 qWarning() << "Invalid pixmap captured from desktop in Core::sendScreenshotToChat(...)";
233 return false;
234 }
235
236 QString screenshot_format = Settings::instance().shareDesktopImageType();
237 QString screenshot_initial_path = Settings::instance().cacheFolder() +
238 QString( "/beesshottmp-%1." ).arg( Bee::dateTimeStringSuffix( QDateTime::currentDateTime() ) )
239 + screenshot_format;
240 QString file_path = Bee::uniqueFilePath( screenshot_initial_path, false );
241
242 if( !screen_shot.save( file_path, screenshot_format.toLatin1() ) )
243 {
244 qWarning() << "Unable to save temporary screenshot in file" << qPrintable( file_path );
245 return false;
246 }
247 screen_shot.reset();
248
249 foreach( VNumber user_id, c.usersId() )
250 {
251 if( user_id != ID_LOCAL_USER)
252 sendFile( user_id, file_path, "", false, chat_id );
253 }
254
255 return true;
256 }
257