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